海量编程文章、技术教程与实战案例

网站首页 > 技术文章 正文

深入设计模式:工厂方法

yimeika 2025-06-22 01:23:42 技术文章 6 ℃

设计模式是软件设计中常见问题的典型解决方案,是针对软件设计中常见问题的工具箱,其中的工具就是各种实践验证的解决方式。即使你从未遇到过这些问题, 了解模式仍然非常有用, 因为它能指导你如何使用面向对象的设计原则来解决各种问题。


可能你做程序开发工作已经好多年,可压根儿不知道单例模式是啥。好多人都是这样的情况,可就算是这样,说不定你在自己都没意识到的时候,就已经用过一些设计模式了。那为啥不花点时间再深入学学它们呢?


本系列将会持续介绍三种主要的模式类别:

  • 创建型模式 提供创建对象的机制, 增加已有代码的灵活性和可复用性。
  • 结构型模式 介绍如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效。
  • 行为模式 负责对象间的高效沟通和职责委派。

这三个类别可能目前看着比较抽象,后续我们针对不同类别,深入学习,了解模式背后的基础性设计理念和原则,并介绍具体使用场景。


工厂方法模式

工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。

假设你正在开发一款物流管理应用。 最初版本只能处理卡车运输, 因此大部分代码都在位于名为 卡车 的类中。

一段时间后, 这款应用变得极受欢迎。 你每天都能收到十几次来自海运公司的请求, 希望应用能够支持海上物流功能。

但是代码问题该如何处理呢? 目前, 大部分代码都与 卡车类 相关。 在程序中添加 轮船类 需要修改全部代码。 更糟糕的是, 如果你以后需要在程序中支持另外一种运输方式, 很可能需要再次对这些代码进行大幅修改。

最后, 你将不得不编写繁复的代码, 根据不同的运输对象类, 在应用中进行不同的处理。


解决方案

工厂方法模式建议使用特殊的工厂方法代替对于对象构造函数的直接调用 (即使用 new运算符)。 不用担心, 对象仍将通过 new运算符创建, 只是该运算符改在工厂方法中调用罢了。 工厂方法返回的对象通常被称作 “产品”。

现在你可以在子类中重写工厂方法, 从而改变其创建产品的类型。但有一点需要注意:仅当这些产品具有共同的基类或者接口时, 子类才能返回不同类型的产品, 同时基类中的工厂方法还应将其返回类型声明为这一共有接口。

所有产品都必须使用同一接口。

举例来说, 卡车Truck 轮船Ship 类都必须实现 运输Transport 接口, 该接口声明了一个名为 deliver交付 的方法。 每个类都将以不同的方式实现该方法: 卡车走陆路交付货物, 轮船走海路交付货物。 陆路运输 Road-Logistics 类中的工厂方法返回卡车对象, 而 海路运输 Sea-Logistics 类则返回轮船对象。

调用工厂方法的代码 (通常被称为客户端代码) 无需了解不同子类返回实际对象之间的差别。 客户端将所有产品视为抽象的 运输 。 客户端知道所有运输对象都提供 交付 方法, 但是并不关心其具体实现方式。


工厂方法模式适合应用场景

当你在编写代码的过程中, 如果无法预知对象确切类别及其依赖关系时, 可使用工厂方法。

工厂方法将创建产品的代码与实际使用产品的代码分离, 从而能在不影响其他代码的情况下扩展产品创建部分代码。

例如, 如果需要向应用中添加一种新产品, 你只需要开发新的创建者子类, 然后重写其工厂方法即可。


工厂方法模式优缺点

优点:

  • 你可以避免创建者和具体产品之间的紧密耦合。
  • 单一职责原则。 你可以将产品创建代码放在程序的单一位置, 从而使得代码更容易维护。
  • 开闭原则。 无需更改现有客户端代码, 你就可以在程序中引入新的产品类型。

缺点:

  • 应用工厂方法模式需要引入许多新的子类, 代码可能会因此变得更复杂。 最好的情况是将该模式引入创建者类的现有层次结构中。

在许多设计工作的初期都会使用工厂方法模式 (较为简单, 而且可以更方便地通过子类进行定制), 随后演化为使用抽象工厂模式原型模式生成器模式 (更灵活但更加复杂)。


Java工厂方法模式讲解和代码示例

使用示例: 工厂方法模式在 Java 代码中得到了广泛使用。 当你需要在代码中提供高层次的灵活性时, 该模式会非常实用。

核心 Java 程序库中有该模式的应用:

  • java.util.Calendar#getInstance()
  • java.util.ResourceBundle#getBundle()
  • java.text.NumberFormat#getInstance()
  • java.nio.charset.Charset#forName()
  • java.net.URLStreamHandlerFactory#createURLStreamHandler(String) (根据协议返回不同的单例对象)
  • java.util.EnumSet#of()
  • javax.xml.bind.JAXBContext#createMarshaller() 及其他类似的方法。

识别方法: 工厂方法可通过构建方法来识别, 它会创建具体类的对象, 但以抽象类型或接口的形式返回这些对象。

最近发表
标签列表