开发者社区> 吞吞吐吐的> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Factory Method模式的误区:Factory Method模式是简化版的Abstract Factory吗?

简介:
+关注继续查看

    FactoryMethod是一个相对比较简单的创建型模式,但是能领悟或者用对的并不多见;很多示例都没有反应出Factory Method的核心思想,只是实现了一个简化版的Abstract Factory,然后给出的解释是Factory Method模式解决“单个对象”的需求变化,Abstract Factory 模式解决“系列对象”的需求变化。

    试想一下,如果把1视为N的一种特殊情况,则一个产品系列可能只包含一个对象;那么我们是不是可以认为Factory Method是一个简化版的Abstract Factory呢?实际上,Factory Method模式与Abstract Factory模式虽然同属于对象创建型模式,并且AbstractFactory通常用Factory Method模式实现,并且效果上都可用于连接平行的类层次,但是这两个模式在思想上有着本质的区别。网上的文章抄来抄去,结果错误也被到处传。上一篇介绍了被普遍误用的Builder模式,这篇继续为Factory Method正名。

 

1. Factory Method (Form《设计模式》 GOF)

1.1 意图

定义一个用于创建对象的接口,让子类来决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类

1.2 别名

虚构造器(Virtual Constructor

1.3 实用性

同时满足下列情况下可以使用Factory Method模式:

  1. 当一个类不知道他所必须创建的类的对象的时候;
  2. 当一个类希望由它的子类来指定他所创建的对象的时候;
  3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。(这个翻译很汗,英文原文是:classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.)
1.4 结构:(直接从书中截的图)

image

 

1.5 补充说明
  1. 上面是GOF对FactoryMethod的阐述,字里行间,都流露出继承思想:父类(Creator)不知道他所必须创建的类的对象(Product),于是就留了个接口,委托给子类(ConcreteCreator)来实现(重写)。
  2. Creator类中还有个AnOperation方法,GOF还专门为这个方法做了注释,该方法是一个Template Method(模板方法),其调用FactoryMethod()。并且在相关模式中,GOF也重复提到:“工厂方法通常在Template Method中被调用”,很多介绍Factory Method的例子,都直接无视这个Method和注释,导致误用Factory Method模式。
  3. 这个类图中,没有画“Client”类,而Abstract Factory中,有画Client类。这里应该不是高兴的时候就画,不高兴的时候就不画,画与不画自有其中的道理。

    继续沿用上一篇的思路,从几个被曲解的例子开始。

 

2.  两个简化版的Abstract Factory模式

2.1 Abstract Factory模式结构图

(直接从书中截的图)

image

2.2 当产品系列中只包含一个对象

Abstract Factory 用于创建产品系列,一个系列的产品可能包含多个(N,N>=1)个对象;但如果我们把1视为N的一种特殊情况,则一个产品系列可能只包含一个对象,则有如下结构:

1. 《大话设计模式》中Factory Method的例子:(从书中截的图)

clip_image001

2. <.Net设计模式(5):工厂方法模式(Factory Method)>

http://www.cnblogs.com/Terrylee/archive/2006/01/04/310716.html, 直接引用的原文中的两个图片:

 

    由于是两个图,我也没有做处理,直接搬过来了;画上聚合线的话,与前面的例子差不多。

2.3 对这两个例子的说明

    GOF在介绍Abstract Factory模式的时候,有说到“AbstractFactory通常用Factory Method模式实现,但它们也可以用Prototype实现”。虽然上面两个例子中,只看其中的局部部分的话,用到了Factory Method模式,但结合原作者们的阐述、及扩展点,全局地看,并没有反映出Factory Method的思想

 

3. Factory Method与Abstract Factory的区别

Factory Method模式与Abstract Factory模式虽然同属于对象创建型模式,并且AbstractFactory通常用Factory Method模式实现,并且效果上都可用于连接平行的类层次(Factory Method不限于此),但是这两个模式在思想上有着本质的区别。我理解的Factory Method与Abstract Factory,有如下几点区别:

3.1 对象职责上:Abstract Factory中的Factory,只具有创建对象(一个产品系列)的唯一职责;而Factory Method中的Creator,往往具有实际的逻辑和意义

    回过头来看Factory Method的结构图,可以看到Creator类中还有个AnOperation方法,GOF还专门为这个方法做了注释,该方法是一个Template Method(模板方法),其调用FactoryMethod()。并且在相关模式中,GOF也重复提到:“工厂方法通常在Template Method中被调用”。也就是说,通常是在Creator类自己的其他方法里面,调用Factory Method方法。为啥会这样子呢?

    GOF用下面这个例子来引出Factory Method模式:

     image

    这个例子中,Application扮演Creator的角色,MyApplication扮演ConcreteCreator的角色。Application是一个鲜活的类,它是对具体事物(应用)的抽象,具有自己的职责,而不仅仅只是new一个Document对象;它的NewDocument方法(Template Method)调用CreateDocument,Application对象其实就是Document对象的使用者(Client);Factory Method突出的是对Procuct(本例中的Document)创建,所以在结构图中,没有出现额外的Client类,也不需要出现。

  (2010-09-29补充 [特别感谢一楼的soudog] :) Factory Method的creator同时包含了不变的代码逻辑和变化部分,但里面的变化部分可以委托子类来重写(override);而abstract facotry把变化部分提取到factory类中,将不变的代码逻辑(Client)与变化部分分离得更彻底,然后通过聚合来连接Client和factory。

3.2 扩展上:Abstract Factory侧重水平扩展,而Factory Method侧重垂直扩展

    “水平扩展”、“垂直扩展”的概念是我自己胡口乱说的,呵呵。可以用下面两个图来说明:

    先看Abstact Factory(留意图中的红色箭头及方向):

image

    Abstract Factory:不同的ConcreteFactory,创建不同的产品系列,Factory之间可以相互替换,从而替换产品系列。Client面向接口(AbstractFactory和AbstractProductA)编程,Factory类封装了对象系列的创建工作,具体的产品也从Client中分离开来,使得我们很容易交换产品系列。图中我们可以看到,新增加的ProductA3/B3和ConcreteFactory3,与原有ConcreteProduct和ConcreteFactory,处于平行的类层次。这就是我所谓的“水平扩展”-_-

    补充:虽然可以增加其他的ConcreteFactory,譬如ConcreteFactory4,让其继承现有的ConcreteFactory,看起来ConcreteFactory4与其他的ConcreteFacotry不再属于同一个类层次,看起来不再“水平”了。但是,这里强调的是Client的视角,从Client看来,ConcreteFactory4与ConcreteFactory1~3,从意义上是等价的,即创建一个系列的产品,且他们之间可以相互替换,以实现替换产品系列。即:从逻辑意义上看,还是可以看作“水平扩展”。

    再看Factory Method(留意图中的深绿色箭头及方向)::

    image

    Factory Method:子类(ConcreteCreator)重写父类(Creator)的创建产品接口(FactoryMethod())。结合Factory Method的实用性及Application/Document的例子,ConcreteCreator该创建什么类型的Product,是依赖于ConcreteCreator自身封装的逻辑来决定的(上一节介绍了,Creator/ConcreteCreator是具有现实意义的类),这里强调的是ConcreteCreator与Creator之间的继承关系,它们处于不同的类层次,这就是我所谓的“垂直扩展”。

    补充:虽然可以增加ConcreteCreator3/ConcreteProduct3,如上图所示,让ConcreteCreator之间看起来不再垂直。但是,这里强调的是Creator与ConcreteCeator、以及Product与ConcreteProduct之间的关系。从Creator的Client(图中没有画出)来看,不同的ConcreteCreator之间是不能替换的。譬如Application/Document的例子,当Client操作的是一个绘图应用,则使用的必然是DrawingApplication和DrawingDocument,而不可能是TextApplication和TextDocument。虽然在“效果”一节中,GOF阐述到:Factory Method可以连接平行的类层次,并以Figure和Manipulator为例,如下图所示:

image

    从图形结构上看,Creator(LineFigure和TextFigure等),与Product(LineManipulator和TextManipulator)之间是处于平行的类层次。但是值得注意的是:Product之间、TextManipulator之间,是不可替换的。Client面向接口(Figure和Manipulator)编程,当Client操作一条线段(Line)时,它必然要使用LineFigure和LineManipulator;而当Client操作一段文本(Text)时,也必然使用的是TextFigure和TextManipulator;ConcreteDocument依赖于Client的上下文才能确定,ConcreteFigure之间是不能相互替换的。抽象的Creator接口,不知道Client的上下文是什么,无从知晓该创建什么Product,于是就委托给子类来重写。Factory Method强调的是Procuct与ConcreteProduct、Creator与ConcreteCreator之间的继承关系,子类(ConcreteCreator)重写父类(Creator)的创建产品接口(FactoryMethod()),从逻辑意义上讲,可以看作“垂直扩展”。

    而在实现一节中,GOF给出的MazeGame的例子:

image

    图中省略了创建的产品。虽然这里可以认为EnchantedMazeGame与BomedMazeGame可以互换,但是留意MazeGame的职责(它是对具体事物[迷宫游戏]的抽象,而不仅仅是一个创建各个Product的接口),以及他的CreateMaze方法(该方法是一个模板方法)。这里反复强调的是继承父类、重写创建Product的接口。

3.3 使用上:Abstract Factory的思想是聚合(Composition),而Factory Method的思想是继承(Inheritance)

    GOF在介绍完5个创建型模式后,有一个讨论小结:“用一个系统创建的那些对象的类对系统进行参数化有两种常用方式:一种是生成创建对象的类的子类,这对应于Factory Method模式”;“另一种对系统进行参数化的方法更多的依赖于对象复合:定义一个对象负责明确产品对象的类,并将它作为该系统的参数,这就是Abstract Factory、Builder和Prototype模式的关键特征。”

    对于Factory Method,以Application/Document为例,Application(Creator)要使用Document(Product),把Document视为Application操作的一个“参数”,则特定的Document(ConcreteProduct)是由具体应用的Application(ConcreteCreator,Creator的子类)来创建的。

    对于Abstract Factory,来看看GOF介绍的实现:

image

    画得比较乱,凑合着看,呵呵。重点是左上方的红色注释部分,其演绎的就是Abstract Factory的Composition思想:MazeGame聚合了一个MazeFactory。

    另外两个需要留意的地方:(1). 注意MazeFactory的职责:只是一组创建对象的接口;(2). MazeFactory包含了一组Factory Method。

 

4. 总结

    Factory Method模式不是简化版的Abstract Factory;相反,Abstract Factory模式中的Factory类,可以视为一个简化版的Factory Method模式(例如本文开头的两个例子),其将Creator的职责单一化了,使之只具有创建的对象的职责。

    Factory Method与Abstract Factory,在效果上都可用于连接平行的类层次(Factory Method不限于此),但是这两个模式在思想上有着本质的区别:

  1. 对象职责上:Abstract Factory中的Factory,只具有创建对象(一个产品系列)的唯一职责;而Factory Method中的Creator,具有实际的逻辑和意义。
  2. 扩展上:Abstract Factory侧重水平扩展,而Factory Method侧重垂直扩展。
  3. 使用上:Abstract Factory的思想是聚合,而Factory Method的思想是继承。

   相关模式:Abstract Factory经常用工厂方法来实现。工厂方法通常在Template Method中被调用


本文转自Silent Void博客园博客,原文链接:http://www.cnblogs.com/happyhippy/archive/2010/09/26/1836223.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Factory Method工厂方法模式(Java代码实现)——创建型模式
Factory Method工厂方法模式(Java代码实现)——创建型模式
30 0
一个Oracle监听问题的网络排查
  今天在梳理一套环境的时候,发现了一个奇怪的问题,应用端连接正常,但是服务端却有些问题。    假设服务端的IP地址为10.129.128.57    使用tnsping本机的服务,竟然抛出了监听的问题。
1152 0
温故而知新:设计模式之抽象工厂(AbstractFactory)
抽象工厂主要用来解决多个系列的对象实例问题。 问题的应用场景(来源于李建忠老师的webcast讲座): 如果有一款游戏,里面有"道路,房屋,隧道,丛林"这四类基本设施,而且不同的地图(比如中国区,印度区,欧美区)这些设施的风格各有特色,比如中国区应该是中国风格,印度区可能是古典风格,欧美区可能是现代风格.
719 0
工厂模式之三 - 抽象工厂(Abstract Factory)模式
抽象工厂(Abstract Factory)模式 不同于简单工厂和工厂方法,抽象工厂用于创建一个产品族, 即抽象工厂模式用于创建一系列类,这些类在业务上有关联。 我们来举个快餐店的例子。 场景:快餐店的套餐分为汉堡和饮料,汉堡可以选鸡肉汉堡,鱼肉汉堡,巨无霸等等,          饮料可以选咖啡,可乐,橙汁等等。
709 0
工厂模式之二 - 工厂方法(Factory Method)
工厂方法(Factory Method)模式又叫做多态性工厂(Polymorphic Factory)。 简单工厂模式的优缺点 优点:将类的创建逻辑从客户端移入工厂类。 缺点:对开-闭原则支持不够,如果有新类加入,必须修改工厂类的逻辑。
906 0
4849
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载