实 现(续)
2) 创建产品 AbstractFactory仅声明一个创建产品的接口 ,真正创建产品是由
ConcreteProduct子类实现的。最通常的一个办法是为每一个产品定义一个工厂方法(参见Factory Method(3 . 3))。一个具体的工厂将为每个产品重定义该工厂方法以指定产品。虽然这样的实现很简单,但它却要求每个产品系列都要有一个新的具体工厂子类,即使这些产品系列的差别很小。
如果有多个可能的产品系列,具体工厂也可以使用Prototype(3.4)模式来实现。具体工厂使用产品系列中每一个产品的原型实例来初始化,且它通过复制它的原型来创建新的产品。在基于原型的方法中,使得不是每个新的产品系列都需要一个新的具体工厂类。
接下来本来是Smalltalk中原型生成对象的例子,这里省略。Smalltalk是一种神奇的语言,需要面向对象的经典书籍都会提到它,但是却没见过哪里真正用到。我们还是提供一个C++的例子。照例先看类图:
这部分代码是前一篇文章中例子的一部分。CustomThemeFactory读取保存在文件中主题信息并生成原型。
readPrototype负责从文件中读出原型。这里省略细节,只要知道最后得到CustomWindow和CustomScrollbar即可。
当createWindow和createScrollbar被调用时,代码分别从CustomWindow,CustomScrollbar克隆出具体的产品。通过指定不同的文件,我们可以产生任意组产品。
3) 定义可扩展的工厂 AbstractFactory通常为每一种它可以生产的产品定义一个操作。产品的种类被编码在操作型构中。增加一种新的产品要求改变 AbstractF actory的接口以及所有与它相关的类。一个更灵活但不太安全的设计是给创建对象的操作增加一个参数。该参数指定了将被创建的对象的种类。它可以是一个类标识符、一个整数、一个字符串,或其他任何可以标识这种产品的东西。实际上使用这种方法, AbstractFactory只需要一个“Make”操作和一个指示要创建对象的种类的参数。这是前面已经讨论过的基于原型的和基于类的抽象工厂
的技术。
C + +这样的静态类型语言与相比,这一变化更容易用在类似于Smalltalk这样的动态类型语言中。仅当所有对象都有相同的抽象基类,或者当产品对象可以被请求它们的客户安全的强制转换成正确类型时,你才能够在 C + +中使用它。Factory Method(3.3)的实现部分说明了怎样在C + +中实现这样的参数化操作。
该方法即使不需要类型强制转换,但仍有一个本质的问题:所有的产品将返回类型所给定的相同的抽象接口返回给客户。客户将不能区分或对一个产品的类别进行安全的假定。如果一个客户需要进行与特定子类相关的操作,而这些操作却不能通过抽象接口得到。虽然客户可以实施一个向下类型转换(downcast)(例如在C + +中用dynamic_cast),但这并不总是可行或安全的,因为向下类型转换可能会失败。这是一个典型的高度灵活和可扩展接口的权衡折衷。
这一部分可以选择在学习了Factory Method模式之后再来重新理解。但是有一点可以肯定的是:当我们需要完成多个类似功能的时候,使用参数区分功能还是直接编写多个函数,绝对是程序员烦恼的源头之一。折衷也好,权衡也好,妥协也好,意思都差不多。
参考资料
动态类型转换:
https://mp.weixin.qq.com/s/DO5NDTfoQx_i3qh8ydww3Q
代码
https://github.com/xueweiguo/OOThinking/tree/master/Aha!DesignPattern/SingletonFactory
类图
https://github.com/xueweiguo/OOThinking/blob/master/Aha!DesignPattern/AhaDesignPattern.EAP
注:
本文中
蓝 {MOD}粗体文字都引自《设计模式》一书。
觉得本文有帮助?请分享给更多人。
阅读更多更新文章,请扫描下面二维码,关注微信公众号【面向对象思考】