《设计模式》—创建型模式—工厂方法模式
一、问题来源
考虑一个应用框架,它可以像用户显示多种文档。不同的实现者继承或实现相应的接口以提供不同文档的解析和显示。对于框架来说,某些操作可以是固定的。以新建文档的过程举例,我们将创建的文档对象添加到文档集合的列表中是固定的。但是,创建文档对象本身这个操作是由具体应用所定义的。因此框架需要将创建文档对象声明为抽象方法。其实现被延迟到子类。
二、类图
从类图中,我们可以看出:在抽象类中,对于产品的操作流程一般是固定的;然而,由于不同子类需要创建不同的产品,因此产品的创建被延迟到子类实现。
三、适用范围
1、当一个类不知道它所必须创建的对象的类的时候
Creator中只知道不能被实例化的抽象产品类。因此,可以声明创建产品的方法返回抽象产品类对象,借助多态去实现其余方法。然而,该方法也只能是纯虚的。
2、当一个类希望由它的子类来制定它所创建的对象的时候
即使Creator知道所有的产品类,由于其是一个框架,不宜把生成具体某种产品的代码写在其实现中。否则继承该类的具体Creator将无法实现定制化操作。因此一个更好的选择是将产品的创建留给ConcreteCreator。
3、当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候
第一句话同2。后面这句话的意思就是对于用户,并不需要知道通过哪个ConcreteCreator完成的产品创建、维护、销毁工作。对客户来说,可能他们只需要点一下按钮。因此说这种帮助子类的代理信息是局部化的,只有ConcreteCreator知道。而ConcreteCreator可能由客户维护也可能由Creator维护(抽象工厂)。
四、参与者
1、Product
定义了抽象产品类
2、ConcreteProduct
具体产品类
3、Creator
(1)声明工厂方法,返回Product子类对象。可以提供默认返回的具体产品对象,因此未必是抽象类。
(2)内部可以封装构建对象的过程。
4、ConcreteCreator
返回对应一个具体应用的具体产品类。
五、优点
1、为子类提供钩子
正如我们前面讨论的,工厂方法提供了抽象方法供子类以实现。这样的方式就是给子类一个钩子,以便子类提供对象的扩展版本。
2、连接平行的类层次
工厂方法并不是只能被Creator调用,客户可以找到一些有用的工厂方法,尤其是在平行的类层次上。那么什么是平行类层次呢?考虑我们前面学过的抽象工厂模式,其中产品和工厂就是一种部分平行的状态。如果抽象工厂提供了创造默认产品的行为,那么每个工厂就可能没有具体的产品类与之对应;如果抽象工厂没有提供默认行为,那么二者就是完全平行的,因为每个具体工厂类都有与之对应的产品类。
六、缺点
容易产生许多功能过于简单的ConcreteCreator类。
客户可能仅仅为了获得一种新的ConcreteProduct,就要创建一个新的Creator与之匹配。如果有很多相似的产品,这种做法看起来尤为浪费,而且容易造成类爆炸。
七、实现
(1)参数化工厂方法模式
用户读取配置文件或系统信息并将工厂方法需要的参数传入以构造不同类型的产品。可以参考qt中QPlatformIntegrationFactory。这个方法用于创建特定系统下的集成化平台。
// Create the platform integration.
QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath);
其中系统的信息就是application根据配置文件以及环境变量所获得的。当然,一般来说这样还是有扩展性的问题,如果我们有新产品的加入,在创建产品处就需要增加分支判断语句。但是qt中将平台名称与插件名称做了直接映射,因此其兼容性还是比较好的。
(2)使用模板以避免创建子类
借助C++的模板元编程功能,我们不必显式的创建一个Creator的子类。但是,这种方式要求客户了解要创建的具体产品类,因此没法以这种方式应用于抽象工厂模式中。
#include <iostream>