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 结构:(直接从书中截的图)

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模式结构图

(直接从书中截的图)

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

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

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

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模式:

这个例子中,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(留意图中的红色箭头及方向):

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(留意图中的深绿色箭头及方向)::

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为例,如下图所示:

从图形结构上看,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的例子:

图中省略了创建的产品。虽然这里可以认为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介绍的实现:

画得比较乱,凑合着看,呵呵。重点是左上方的红色注释部分,其演绎的就是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中被调用

Factory Method模式的误区:Factory Method模式是简化版的Abstract Factory吗?相关推荐

  1. 我的实用设计模式之Simple Factory,Factory Method和Abstract Factory

    更新1:更新Factory Method部分,说明文中使用"参数化工厂方法"的实现,同时加入经典Factory Method的实现进行比较. 更新2:更新Abstract Fact ...

  2. 设计模式之抽象工厂模式(Abstract Factory)摘录

    面向对象系统的分析和设计实际上追求的就是两点:高内聚(Cohesion)和低耦合(Coupling). 23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式包括:1.Fa ...

  3. 设计模式学习笔记三——Abstract Factory模式

    动机:实现一系列相互依赖对象的创建,通过封装系列对象创建来隔离对象创建和客户程序,从而能够灵活提供更多系列对象创建和系列对象间的切换,而不需要改变客户程序. 应用:多种风格软件界面控件的创建.对应多种 ...

  4. 设计模式学习总结1 - 创建型1 - Abstract Factory抽象工厂模式

    AbstractFactory抽象工厂模式(创建型) 作用: 这种模式支持创建不同的对象,这些对象功能接近且一般都是在一起创建的.抽象工厂被具体化成不同的工厂来创建类似产品的不同产品.这种模式将类于使 ...

  5. 抽象工厂模式 Abstract Factory Pattern

    源地址 抽象工厂模式 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂.该超级工厂又称为其他工厂的工厂.这种类型的设计模式属于创建型模式,它提供了一种创建 ...

  6. 设计模式 - 抽象工厂模式(abstract factory pattern) 详解

    抽象工厂模式(abstract factory pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/270916 ...

  7. Factory Method vs Abstract Factory

    点开这篇着你已经大致对工厂方法有了一定的了解.但为什么依然对这两者的区别不是很明白,在搜索了一天.看了许多文章后我有了一点想法,在这里分享并记录一下. 引用SO的一段文字: One differenc ...

  8. 抽象工厂(Abstract Factory)模式

    >>所谓工厂,是将零件组装成产品的地方,这是一项具体的工作. >>抽象工厂的工作是将"抽象零件"组装为"抽象产品". >>在 ...

  9. 设计模式之笔记--抽象工厂模式(Abstract Factory)

    抽象工厂模式(Abstract Factory) 定义 抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 类图 描述 多个抽象产品 ...

最新文章

  1. iOS下JS与OC互相调用(四)--JavaScriptCore
  2. python【蓝桥杯vip练习题库】ALGO-79删除数组零元素
  3. PDF页眉页脚怎么设置
  4. 阿里云徐立:面向容器和 Serverless Computing 的存储创新
  5. 贝塞尔曲线工具css,如何反转CSS中的贝塞尔曲线的实现方法
  6. mysql32位的能装在64位的电脑上吗,mysql32位能装64位电脑【excle中怎么将log值变回原来的数据库】...
  7. 如何优雅的关闭 Spark Streaming 程序(2种思路)
  8. 服务器自动post,Go Web服务器自动重定向POST请求
  9. splice方法_JavaScript数组_数组方法【一】(二十六)
  10. 软件测试思维导图大全
  11. fc安卓模拟器_MAME街机模拟器0.224经典游戏全收藏
  12. 苹果7pnfc功能门禁卡_苹果7手机nfc怎么开启 苹果手机门禁卡nfc功能
  13. Win10资源管理器闪退解决办法
  14. Mysql创建Create Function
  15. This application is currently offline解决办法
  16. HTML学习13:div和表格布局
  17. IHG Connect,给旅人一个温暖的家
  18. 分享35款非常有用的免费字体
  19. mysql按照汉字拼音进行order by排序
  20. 【小梅哥FPGA进阶教程】第九章 基于串口猎人软件的串口示波器

热门文章

  1. Effective_STL 学习笔记(八) 永不建立 auto_ptr 的容器
  2. FileEncodingApplicationListener使用以及原理
  3. Vue.js第六课 计算属性
  4. hive 函数 Cube
  5. cocos2dx-3 addImageAsync陷阱
  6. Python丨为什么你学不好设计模式?
  7. oracle:平均分大于78的女同学的学号、姓名、平均分
  8. jqgrid本地数据例子_微型数据转换器如何通过更小尺寸为您带来更多价值
  9. ts可展开注释_TS语法之装饰器(注解)
  10. MySQL高级 - 锁 - 锁的概述及分类