3.3-FactoryMethod-工厂方法-创建型模式
又称虚构造器(virtual constructor)
用途
定义一个用于创建对象的接口,让子类决定实例化哪一个类。 Factory Method 使一个类的实例化延迟到其子类。
示例
框架用抽象类定义和维护对象之间的关系。 Eg:框架定义了 App 抽象类,它包含一个 Document 抽象内容。但是 App 类无法确认应当实例化哪个 Document 的具象子类:
- 方法:
- 抽象类 App 中提供接口 CreateDocument。
- 具象 App 子类重载接口 CreateDocument,并创建自己要用到具象的 Document

结构

- Product:定义工厂方法要创建的对象的类别
- ConcreteProduct:
- Creator:抽象工厂,定义用于返回 Product 的工厂方法(接口),该接口可以是抽象的,也可以提供一个默认实现返回缺省的 ConcreteProduct
- ConcreteCreator:具象工厂,重载工厂接口
说明:
- Creator 依赖子类重载工厂方法以返回合适的 ConcreteProduct
适用性
- 一个类不确定自己要创建的对象的类
- 一个类希望由子类指定自己创建的对象的类
优缺点
工厂方法的潜在缺点:客户可能只是为了创建一个特定的 ConcreteProduct 对象,就必须创建 Creator 的新的子类
优点:
- 工厂方法不再将应用相关的类绑定到程序代码中。代码只处理 Product 接口
- 可以为子类提供钩子 Hook(提供合理的缺省实现)
- 可以连接平行的类层次:例如图形类和用户的操作是平行的类层次,而抽象父类 Figure 可以提供 CreateManipulator 方法连接 Manipulate 类层次,并为子类提供默认实现

实现
- Creator 可以是抽象类,也可以是提供了缺省实现的具象类
- 抽象类不提供默认实现,可以避免不得不实例化不可预见类的问题
- 具象类:这种情况比直接 new 个实例具有更好的灵活性
- 参数化工厂方法:这允许工厂方法创建多种类型的对象。工厂方法可以采用一个标识(指定要被创建的对象种类的参数)区分不同类型的对象(这些对象都必须是 Product 的子类型)
- 重定义一个参数化的工厂方法使你可以简单而有选择性地扩展或改变一个 Creator 生产的产品。注意最后需要调用父类的 Create
- 命名约定:使用命名约定是一个好习惯,它可以清楚地说明你正在使用工厂方法

Cpp 中的工厂方法:
- cpp 中工厂方法通常是虚函数,且常常是纯虚函数。因而在 Creator 的构造器中不要调用工厂方法——在 ConcreteCreator 中该工厂方法还不可用。
- 正确的方法:懒初始化:构造器中只是简单地将_product 初始化为 0,具体产品的初始化方法放在 getProduct 中进行(若产品存在则返回产品,产品不存在则创建),示例代码如下

- 利用模板避免创建子类:工厂方法另一个潜在的问题是它们可能仅为了创建适当的 Product 对象而迫使你创建 Creator 子类。
在 C++中另一个解决方法是提供 Creator 的一个模板子类,它使用 Product 类作为模板参数:

相关模式
抽象工厂 VS 工厂模式
不同点: 抽象工厂是针对多个产品族而言的,即每个工厂可以创建多种不同类型的产品。例如,一个奔驰工厂可以创建奔驰轿车、奔驰 SUV、奔驰 MPV 等。
- 抽象工厂需要为每个产品的创建提供一个接口;或者需要提供一个创建多种产品的接口。 工厂方法是针对一个产品等级而言的,即每个工厂只负责创建一种类型的产品。例如,一个轿车工厂只能创建轿车,不能创建 SUV 或 MPV。
- 工厂方法只需要实现一个接口,该接口只包含了创建一个产品的方法。
共同点: 抽象工厂和工厂方法都是将对象的创建延迟到其子类实现
其他相关模式
Abstract Factory(3.1)经常用工厂方法来实现。Abstract Factory 模式中动机一节的例子也对 Factory Method 进行了说明。 工厂方法通常在 Template Method(5.10)中被调用。在上面的文档例子中,NewDocument 就是一个模板方法。 Prototype(3.4)不需要创建 Creator 的子类。但是,它们通常要求一个针对 Product 类的 Initialize 操作。Creator 使用 Initialize 来初始化对象,而 Factory Method 不需要这样的操作。




