论坛首页 Java企业应用论坛

Factory Method属于类模式还是对象模式的疑惑及解惑

浏览 14541 次
该帖已经被评为良好帖
作者 正文
   发表时间:2006-12-03  
在GOF《设计模式-可复用面向对象软件的基础》3.3节Factory Method的标题中(Factory Method工厂方法——对象创建型模式),将该模式的类型指定为“对象创建型模式”,在学习的过程中总感觉有些疑惑,因为在意识中我觉得应该属于“类创建型模式”才对。下面是对这一疑惑的陈述和最后解惑。
 
疑惑
为什么我觉Factory Method是类创建型模式
第一、类创建型模式和对象创建型模式的核心区别为:“类创建型模式将对象的部分创建工作延迟到子类中,而一个对象创建型模式将它延迟到另一个对象中”(设计模式引言1.5节),而Factory Method 模式的意图为“定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类”,这正好与类创建型模式相吻合;
第二、我们可以通过Template Method(模板方法-类行为型模式)来进一步说明,Template Method定义了一个操作中算法的骨架,而将一些步骤延迟到子类中,从而使得子类可以不改变算法的结构既可重定义该算法的某些特定步骤。这与Factory Method的意图(定义一个用于创建对象的接口,而让子类来决定实例化哪一个类,从而使一个类的实例化延迟到子类,给子类带来了灵活性)从层次的角度来说正好相同,而不同的只是Template Method 延迟的是操作行为,Factory Method 延迟的是实例化对象。
 
再疑惑
后来在该书第一章引言的模式组织编目中,发现确实是把Factory Method归入了类创建型模式,这不由得又怀疑难道是3.3节的标头中模式类型出现的印刷错误……
 
疑惑释去
随着对设计模式理解的逐渐深入,发现其实将某个模式分为对象模式还是类模式,并不是能够很严格和清晰的,具体分类根据观察的角度不同会出现不同的结果。对于Factory Method模式,随着其使用场景的不同,其所属的类型也不大相同(如果非要给个分类的话),下面分别用两个应用场景来描述和理解。
 
应用场景一:(该模式动机中所举示例)一个文档应用框架,在该框架中有两个主要的抽象类Application和Document,对于一些操作发生时,比如创建新文档或打开文档时,Application便需要创建Document对象的实例,然而要创建的Document对象是与特定应用相关的,作为框架抽象类的Application无从知晓,所以这个时候通过引入Factory Method模式来解决这个尴尬的局面,Factory Method将创建对象的操作分离出来用一个接口来定义,子类可以重新实现该接口从而创建特定于应用的正确对象。
在该场景中,通过类创建型模式来理解Factory Method要好一些,通过Factory Method,父类为子类提供了一个挂钩,通过该挂钩子类可以具体实现或扩展父类的对象创建接口。
 
应用场景二:(该模式效果部分示例)可以被交互操作的图形应用,在该应用中图形的操作从图形对象(Figure)中分离出来,封装成独立的Manipulator对象,Manipulator负责对图形的操作及保存操作过程中图形的相应状态,在这里图形(Figure)通过Factory Method创建和自己匹配的Manipulator对象。
在该场景中,通过对象创建型模式来理解Factory Method要好一些,因为在这里Factory Method所创建的对象Manipulator不为图形Figure自己使用,而是提供给客户端Client,这样Client所使用的对象Manipulator,是通过另一对象Figure来创建的,这正好比较符合对象创建型模式的特征“而一个对象创建型模式将它延迟到另一个对象中”。
 
        通过分析总结就是:如果创建的对象是自己用,那就看作类创建型模式理解较好;如果创建的对象是提供给外界对象用,那就看作对象创建型模式理解较好。
        以上是我的理解,欢迎交流
   发表时间:2006-12-03  
我认为你举的应用场景一和应用场景二都说明了Factory Method是类型模式,而不是对象模式。
另外你的引用也不正确,设计模式的书中完整的话是这样的。
引用
类型模式是处理类和之类之间的关系,这些关系是通过继承建立的,是静态的,在编译时刻便确定下来了。对象模式是处理对象之间的关系,这些关系在运行的时候是可以变化的,更具动态性。

为什么说Factory Method是类模式,而Abstract Factory是对象模式呢?
我的理解是,Factory Method在你设计的时候,你需要创建一个对象,然后你不知道如何具体的创建某个对象,那么你就将这个行为延迟到你的子类中去,这种情况下,一般Factory Method都是抽象方法,强迫子类必须重写该方法。那么你在设计这个的时候,就已经确认了如果client需要使用该类,必须继承该类,并且实现抽象方法。
Abstract Factory是通过抽象一系列产品接口,然后通过具体的工厂来完成这创建对象的任务,当然这个也存在类的继承。但是他并不是不知道如何创建这个对象,而是为了方便以后扩展而把他延迟到子类中去,不需要强迫抽象工厂的使用者继承抽象工厂,所以他是对象模式。当然如果你需要扩展新的品种,你仍然需要继承抽象工厂。
BTW:应用场景二很像抽象工厂,但是不是。
0 请登录后投票
   发表时间:2006-12-04  
geradle 写道
我认为你举的应用场景一和应用场景二都说明了Factory Method是类型模式,而不是对象模式。
另外你的引用也不正确,设计模式的书中完整的话是这样的。
引用
类型模式是处理类和之类之间的关系,这些关系是通过继承建立的,是静态的,在编译时刻便确定下来了。对象模式是处理对象之间的关系,这些关系在运行的时候是可以变化的,更具动态性。


我的引用有两处如下,不知道你说的不正确在什么地方,请指出以便更正
引用
类创建型模式将对象的部分创建工作延迟到子类中,而一个对象创建型模式将它延迟到另一个对象中
引自设计模式引言1.5节(因为目前手边没有这本书,多少页就不清楚了:))
引用
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类
引自Factory Method 模式意图

对于应用场景一和应用场景二是否都说明了Factory Method是类型模式,我觉得用何种模式(类模式/对象模式)去理解是一个更好的问题,而不是绝对的问题,比如在该节中GOF指定为对象模式,而且在文中并没有再提在某种情况下可以用类模式理解

在这里我指出场景二用对象创建型模式去理解要好一些,是因为客户端Client将创建对象Manipulator的职责委托给了图形Figure,而不是Client去继承Figure并扩展创建对象的接口
0 请登录后投票
   发表时间:2006-12-04  
引用

因为在这里Factory Method所创建的对象Manipulator不为图形Figure自己使用,而是提供给客户端Client,这样Client所使用的对象Manipulator,是通过另一对象Figure来创建的,这正好比较符合对象创建型模式的特征“而一个对象创建型模式将它延迟到另一个对象中”

我认为你对对象模式理解不正确。你举的这个例子中,Manipulator本来就是Figure本身的职责,这里只是把他分离出来,方便抽象。不能说因为这个对象不是给Figure自己用的,而是提供给客户端client的,就是“对象创建模式的特征吧”。
而且我不知道你说的对象创建模式是什么,也不知道其特征是什么。
0 请登录后投票
   发表时间:2006-12-04  
geradle 写道
引用

因为在这里Factory Method所创建的对象Manipulator不为图形Figure自己使用,而是提供给客户端Client,这样Client所使用的对象Manipulator,是通过另一对象Figure来创建的,这正好比较符合对象创建型模式的特征“而一个对象创建型模式将它延迟到另一个对象中”

我认为你对对象模式理解不正确。你举的这个例子中,Manipulator本来就是Figure本身的职责,这里只是把他分离出来,方便抽象。不能说因为这个对象不是给Figure自己用的,而是提供给客户端client的,就是“对象创建模式的特征吧”。
而且我不知道你说的对象创建模式是什么,也不知道其特征是什么。

在Gof<设计模式>中根据两种准则进行的分类,一种准则是目的,即根据模式主要是用来干什么的,根据该准则将模式分为创建型、结构型和行为型;另一种准则是范围,即模式主要是用于类还是用于对象,类模式处理类之间的继承关系,对象模式处理对象之间的关系。由于几乎所有的模式都存在类的继承,所以类模式只指那些集中于处理父类和子类继承关系的模式,而大部分划分到了对象型模式中,这种划分方式目的之一也是为了要突出“面向接口编程,优先使用对象组合”的设计原则。

为了说明将示例场景二划分为对象创建型模式,我再举一个类似的例子,就是jdk提供的集合类层次结构,在集合类层次中每一种具体的集合类Collection都有一种迭代器Iterator和其对应(这里你也可以理解Iterator也只是把本属于Collection中的迭代行为进行了分离),在用户Client需要创建一个具体集合如ArrayList的迭代器时,Client不是直接创建而是通过ArrayList继承的接口Iterator Collection.iterator()进行创建,在这里Client将创建职责委托给了集合对象自己。
0 请登录后投票
   发表时间:2006-12-04  
为了增强对比直观性,我把上面三种场景应用的结构图贴上来

场景应用一:文档应用框架下的结构图


场景应用二:Figure图形处理应用下的结构图


场景应用一:jdk集合迭代器的结构图
0 请登录后投票
   发表时间:2006-12-05  
唉,没有人说Java的Iterator是对象模式呀?
Iterator本身就是另外一种模式啦。
你举的场景二和场景三不是一样的么。
我觉得你没有看我的回复,或者我没有说清楚吧
0 请登录后投票
   发表时间:2006-12-05  
geradle 写道
唉,没有人说Java的Iterator是对象模式呀?
Iterator本身就是另外一种模式啦。
你举的场景二和场景三不是一样的么。
我觉得你没有看我的回复,或者我没有说清楚吧

我列举的场景三,并不是说明Iterator模式,而是集合类中产生Iterator的工厂方法,是Factory Method模式;

场景二和场景三是一样的,而且我的观点是在这两种场景中,将Factory Method用对象创建型模式理解更好;

我很仔细的看了你的回复,你的观点是在这些使用场景中都说明Factory Method是类模式,并通过和Abstract Factory作比较说明这一观点。

这样我们试试,既然你用Abstract Factory表达对象模式,那么我们可不可以将Figure和Collection看作Abstract Factory的简化版(从创建一系列相关对象简化为创建一个对象),当然如果再增加一个类似的平行对象层次,比如对Figure我们除了分离出操作对象Manipulator,我们再分离出一个修饰类对象Decorator(不要考虑Decorator模式),这时虽然我们可以独立出创建Manipulator和Decorator的抽象工厂为单独的类,但是我们暂时把抽象工厂并到Figure中, 类的结构图如下,这样之后不知道你能不能有些新的理解
0 请登录后投票
   发表时间:2006-12-07  
我还是没有任何新的想法。
首先我要阐明几点,我不是用Abstract Factory来表达对象模式,而是该模式符合对象模式的特点。
我的观点是你举的那个Figure and manipulator的例子中,Factory Method这个Pattern是运用于 AbstractFigure and AbstractManipulator两个类上。我认为当你设计出了这两个类,那么该设计场景应该已经完成。所有Factory Method与你的client无关。如果你client需要使用concrete figure and manipulator你需要通过继承来产生新的类。
BTW:我对Decorator模式的理解也与你不一致。不知道你上图的Decorator模式用于装饰哪个类。
0 请登录后投票
   发表时间:2006-12-07  
我上面所指的Decorator,不是为了引入Decorator模式,只是为了增加一个和Manipulator平行的兄弟类,比如这个类可以为Figure添加颜色,修饰边框等等,这样Figure就可以把创建这些对象的工作移到抽象工厂中,但是当这种平行的兄弟类型比较少时,比如只有一个Manipulator,所以可以合并到Figure类中以简化设计。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics