“工厂模式”
工厂模式应该是最熟悉使用最为广泛的一种模式了。其作用也很明显:将类的实现细节与其使用者隔离开来,使其对使用者不可见,当需要生成某个类的实例时,使用者通过调用工厂方法来获取实例。这样使用者本身不需要了解类的任何实现细节,也不需要维护实例的生命周期,只要直接拿来用即可。一个典型的工厂模式的代码如下:
public class PersonFactory{
// person是一个抽象
public Person newInstance();
}
// 调用者代码:
Person p = PersonFactory.newInstance();
上述代码在简单的项目中十分常见,但是确切的说,这种用法并不是真正的工厂模式,或者可以说根本就没有所谓的工厂模式。在GOF中定义的只有工厂方法模式和抽象方法模式。上述的这种用户其实是一种叫做简单工厂的模式。简单工厂模式与前两种模式有很大的差别,它根本没有进行任何抽象,简单来说就是定义了一个生成对象的工具类。例如,上例中person如果有Girl和Boy两个子类的话,用简单工厂实现的代码如下所示:
public class PersonFactory{
// person是一个抽象
public Person createBoy(){
//构造一个新的Male对象
}
public Person createGirl(){
//构造一个新的FeMale对象
}
}
// 调用者代码:
Person boy = PersonFactory.createBoy();
Person girl = PersonFactory.createGirl();
也即,简单工厂会为Person的每一个子类定义一个方法返回相应的对象。如果仅仅是为了隔离变化,使用这种方式还是可取的。但是这种方式是违背了OOP原则中“开闭原则”的,因为每一个子类的添加都会对工厂类造成影响。一种更好的实现方式是使用前面介绍的工厂方法模式和抽象工厂模式。
工厂方法模式
书中对工厂方法模式的描述如下:
Exposes a method
for creating objects, allowing subclasses to control the actual creation process.
即抽象出一个创造对象的
方法,将真正的创造留到子类中实现。注意这里强调的是一个“方法”,工厂方法模式就是抽象了一个方法。所以,只要你使用了一个抽象方法来返回一个抽象类,就可以说是在使用工厂方法模式了。工厂方法模式的典型类图如图1所示。图中
在抽象类Creator中声明了抽象方法FactoryMethod(),其实现是在子类ConcreteCreator中,返回了ConcreteProduct的实例对象。使用了工厂方法对创造方法进行抽象后,符合了“开闭原则
”。当需要给Product增加一个子类时,只需要新建一个Creator类的子类,并在其工厂方法实现中返回Product相应子类的实例即可,而无需对原有类进行任何修改。这是系统扩展的一个可能方向(垂直方向),同时系统也可能朝着另一个方向进行扩展(水平方向):拿简单工厂中的例子来说,因为人都是有肤色的,如果要对创造的boy和girl赋予不同的肤色,即可能有黄色、黑色等,而不是原来的一种。在这种情况下,就不能简单地通过扩展工厂方法模式中的类来实现了,因为这时是新建了一个平行的产品线。解决这个问题的一个方法是使用抽象工厂模式。
抽象工厂模式
书中对抽象工厂模式的描述如下:
Provide an interface
that delegates creation calls to one or more concrete classes in order to deliver specific objects.
抽象工厂模式提供了一个创建产品族的抽象类(接口)
,其实现是在具体子类中完成的。注意这里强调的是抽象出一个类,这个类中声明了创建一个产品族的方法。通常的做法是为产品族的每一个产品都声明一个抽象方法(即工厂方法)。这也说明了工厂方法和抽象工厂并不是一个层面的概念(类和方法的差别),前者只是后者赖以实现的一种可行方式
。抽象工厂模式的类结构图如图2所示。
该图中,抽象类AbstractPlatform中声明了两个工厂方法,分别用于创建ProductOne和ProductTwo。在其两个子类中分别实现了这两个方法来获取相应的对象。
抽象工厂模式解决了简单工厂模式中的问题,但是它也不是完全满足“开闭原则”的。从类图中可知,当需要添加一条新的产品线时,可以简单地通过扩展一个AbstractPlatform类的子类来实现,这一方面是满足开闭原则的;但如果是要在产品线上增加一个新的产品呢?此时不得不修改原来各个类的实现,分别加上新的产品的工厂方法。
工厂模式之上的工厂模式
工厂模式通过添加额外的工厂类对使用者隔离了子类实现的细节,但是这种隔离是建立在知晓相应工厂类的基础上的。比如, BoyFactory屏蔽了Boy的实现细节,返回了Person的抽象,使用者虽然可以不用知晓Boy类的存在,但是为了达到这一目的,它必须获取一个BoyFactory的对象。也就是说其实是将对Boy的依赖关于转移到了BoyFactory上。对比下面两种调用方法即知:
// 没有使用工厂模式时
Person boy = new Boy();
// 使用了工厂方法模式时
Factory factory = new BoyFactory();
Person boy = factory.createPerson();
这时,为了进一步解耦这种依赖关系,可以在工厂模式之上再包装一层工厂模式,即通过工厂模式来获取BoyFactory这些工厂类。
从上面也可获知设计模式解耦类关系的一般做法便是在两个类之间添加第三个类用于处理这两个之类的关系。原有的依赖关系并没有消除,而只是转移到了第三个类身上。
工厂模式本质上是相当于IOC的type2。即把Factory看作一个容器,使用者依赖于这个容器来获取实例对象。如果想要完完全全在代码中消除这种依赖关系,可以使用IOC的type3,也即依赖注入(DI),将类之间的依赖关系置于配置文件中,容器通过配置文件主动注入依赖关系。使用者不需要主动获取对象实例,直接拿出来用便可。
- 描述: 工厂模式类图
- 大小: 3.8 KB
- 描述: 抽象工厂模式类图
- 大小: 62.4 KB
分享到:
相关推荐
设计模式随笔系列 鸭子问题分析的很到位
设计模式随笔,通过C#进行分析,与NET设计模式风格差不多,整理得挺辛苦。
一年级数学第一学期教学随笔.pdf
一年级语文教学随笔.pdf
经典 电子工程师设计经验随笔 快点下载!!
教育行业周随笔:一对一教培模式简析
关于小学一年级数学下册教学随笔.docx
一年级上册道德与法治教学随笔.docx
苏教版一年级数学教学随笔.docx
Lotus Notes程序设计随笔 作者 李建壹 小路哥
教师随笔-小班教师政治随笔5篇.docx
容斋随笔
工作随笔一瞬间的心动.docx
Lotus_Notes程序设计随笔(精典)
完整的学习JAVA的随笔
《认识人民币》教学片段设计随笔.docx
留守儿童教育随笔.doc
小学一年级数学教学随笔.doc