意图
为父类声明一个创建对象的方法(工厂方法),让子类决定创建哪一个类的对象。
别名
虚构造器(Virtual Constructor)
动机
背景
有两个类,Application和Document,Application可以创建Document。
问题
特定Application子类创建特定Document子类,但是Application不知道需要创建哪个Document子类对象,所以给Application一个工厂方法(虚函数)来创建Document子类对象,让Application的子类来决定要创建哪个Document子类的对象。
示例图形
适用性
- 当一个类不知道它所创建的对象的类是什么,或如何创建的时候。
- 当一个类希望由它的子类来指定它所创建的对象的时候。
结构
参与者
- Product:工厂方法所要创建的产品的抽象类。
- ConcreteProduct:Product的具体子类。
- Creator:声明工厂方法(可为抽象方法),该方法返回一个Product对象。
- ConcteteCreator:重定义工厂方法来返回ConcreteProduct实例。
协作
Creator将创建ConcreteProduct实例的任务延迟到ConcteteCreator。
效果
- 潜在缺点:客户可能仅仅为了创建一个特定的ConcreteProduct,而不得不先创建一个ConcteteCreator。
- 用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。
-
连接平行的类层次,如图:
实现
- Factory Method模式有两种情况:
- Creator工厂方法只提供声明而不提供实现。
- Creator中的工厂方法提供默认实现。
- 参数化工厂方法:
- 工厂方法接受一个参数,通过参数得知要创建的Product类型。
- 子类可以重定义该工厂方法,预先处理部分子类感兴趣的参数对象,将其他参数对象延迟给父类处理。
- 在C++中,注意在Creator的构造函数中不要调用工厂方法,因为此时工厂方法还没表现出虚函数性质。(详细见C++单继承相关笔记:在构造或析构基类时,如果调用了某个虚函数,则这个虚函数使用与当前构造函数或析构函数所属类型相对应的虚函数版本)
-
可以配合Lazy Initialization使用来达到优化性能和避免上述问题的目的:
- 可以为Creator提供一个模板子类StandardCreator,通过传入ConcreteProduct从而避免创建Creator子类。
- 命名约定:使用命名约定让别人知道你在使用工厂方法。如MacApp中,工厂方法的形式:Class * DoMakeClass()。
- 相关模式:
- (3.1)Abstract Factory经常用Factory Method来实现。
- (5.10)Template Methods通常调用Factory Method。
- (3.4)Ptototype不需要创建Cteator的子类,但是它们通常要一个针对Product类的Initialize操作。