工厂方法模式 - 创建型模型

发布时间:2012-09-20 16:19:30   来源:文档文库   
字号:

前言

创建型模式抽象了实例化过程。它们帮助一个系统独立于如何创建、组合和表示它的那些对象。一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化托给另一个对象。随着系统演化得越来越依赖于对象复合而不是类继承时,创建型模式变得更为重要。接下来,我们马上进入对第一个创建型模式的介绍——工厂方法模式。

动机

软件系统中,经常面临着某个对象的创建问题。由于用户需求的改变,该对象的具体实现时常面临着剧烈的变化,但是其所固有的接口却是比较稳定的,如何来应对这种需求上变化?通过封闭机制来隔离这个易变对象的变化点,使系统中依赖于该对象的对象不会随着需求的改变而改变,保持系统一定的稳定性和健壮性。这就是工厂方法善于解决的方面呢。

意图

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

结构图

1. 抽象工厂(creator)角色:是工厂方法模式的核心,任何通过该模式创建对象的具体工厂类都须实现该接口

2. 具体工厂(ConcreteCreator)角色:实现了抽象工厂类的具体工厂类,包含与应用程序相关的逻辑,http://ming.ttplay8.cn 被客户端调用以生成具体的产品对象。在上图中类BMWCreatorBENZCreator就是两个具体的工厂实现类,用于创建不同实现的Car对象

3. 抽象产品(Product)角色:工厂方法所创建的对象的父类型,也就是具体产品对象的共同父类或者说是共同拥有的接口。在上图中,这个角色为Car

4. 具体产品(ConcreteProduct)角色:实现了抽象产品接口的产品。每个具体产品与创建自己的具体工厂是一般来说是一一对应。上图中,BMWBENZ就是两个具体的具体产品类

代码示例

1: public abstract class Car{

2: public abstract void Move();

3: public abstract void Stop();

4: }

5:  

6: public class BMW extends Car{

7: public void Move(){

8: System.out.println("BMW is Moving!");

9: }

10: public void Stop(){

11: System.out.println("BENZ is Stopping!");

12: }

13: }

14:  

15: public class BENZ extends Car{

16: public void Move(){

17: System.out.println("BENZ is Moving!");

18: }

19: public void Stop(){

20: System.out.println("BENZ is Stopping!");

21: }

22: }

23:  

24: public abstract class Creator{

25: public abstract Car factory();

26: }

27:  

28: public class BMWCreator extends Creator{

29: public Car factory(){

30: return new BMW();

31: }

32: }

33:  

34: public class BENZCreator extends Creator{

35: public Car factory(){

36: return new BENZ();

37: }

38: }

39: http://dudu.qqq23.com  

40: public class Client{

41: public static void main(String[] args){

42: Creator c1=new BMWCreator();

43: Creator c2=new BENZCreator();

44:  

45: Car bmw=c1.factory();

46: Car benz=c2.factory();

47:  

48: bmw.Move();

49: bmw.Stop();

50:  

51: benz.Move();

52: benz.Stop();

53: }

54: }

从上面代码中,我们可以很清楚地看到,工厂方法实现的一般做法。从客户端代码上来看,我们均是操作抽象类对象,这也是面向接口编程的核心。需要创建具体产品对象,只需要首先获取对应的产品工厂,再由其创建具体产品对象。在这里,我们可以看到:工厂方法模式实现时,客户端需要决定实例化哪一个具体工厂来创建特定的产品对象,对比简单工厂模式,工厂方法把内部逻辑判断转移到了客户端代码来进行,想要实例化新的产品对象,只需要修改客户端同时添加对应的具体工厂类,而不需要修改工厂类,符合了面向对象的开闭原则“——对扩展开放,对修改关闭。而简单工厂模式的最大优点在于工厂类方法中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对客户端来说,除去了与具体产品的依赖,但是当添加新的产品时,就不得不修改工厂类逻辑,违背了开闭原则

现实场景

在实际的运用场景中,工厂方法应该是最被常用的模式之一呢。不仅因为此模式实现过程的简约,更是因为其实用性。应该说,在任何商业软件系统中都不乏工厂方法模式的身影,比如利用工厂方法模式切换各种数据库示例,由于主流的数据库几乎都支持增、删、改、查的功能(即crud),换句话来说就是各数据库所支持的接口都是相同的,但是不同的数据库有不同的实现方式,通过工厂方法模式,我们就可以很方便地动态创建各种接口相同但是实现不同的数据库操作类对象。具体实现的方式与示例代码的实现框架一致,这里就不重复举例呢。

实现要点

1. Factory Method模式有两种方式:一是Creator类是抽象类且它不提供其所声明的工厂方法实现;二是Creator类是一个具体类并提供其所声明的工厂方法的默认实现

2. 工厂方法的作用不仅仅局限于对象的创建上,同时可以在工厂方法中完成对各种对象或者资源的初始化,各种参数的设置等

3. 在工厂方法的实现过程中,通常一个特定产品对应一个特定的具体工厂,即所谓的一对一关系。而不管工厂还是产品都是针对统一的接口来编码实现。典型的面向接口编程方式

运用效果

1. 用工厂方法在一个类的内部来创建一个对象通常比直接实例化一个对象更加灵活方便

2. Factory Method通过面向对象的方法,将对象的创建工作延迟到子类,提供了一种灵活的扩展方式,很好地将产品与客户端原本的紧耦合变成松耦合关系。

适应性

1. 当一个类不知道它所必须创建的对象的类的时候

2. 当一个类希望由它的子类来指定它所创建的对象的时候

3. 当类将创建对象的职责委托给多个帮助子类中某一个,并且希望将哪一个帮助子类是代理者这一信息局部化的时候

相关模式

1. 工厂方法模式与抽象工厂方法模式:这两个模式都可以组合使用,详细地说明请参考下一代对抽象工厂方法模式的讲解分析。

2. 工厂方法模式与模板方法模式:这两者外观类似,都有一个抽象类,然后由子类来提供一些实现,但是工厂方法模式的子类专注的是创建产品对象,而模板方法模式的子类专注的是为固定算法骨架提供某些步骤的具体实现。这两个模式可以组合使用,通过在模式方法模式里,通过工厂方法来创建模板方法所需要的对象。

总结

工厂方法模式的本质是:延迟到子类来选择实现。工厂方法很好地体现了开闭原则和依赖倒置原则。开闭原则告诉我们对扩展开放,对修改关闭,在工厂方法模式中,我当我们需要添加新的产品对象时,只需要根据产品接口实现新的产品对象以及根据抽象的工厂方法接口来实现新的具体工厂,然后通过相同的逻辑利用对应的具体的工厂方法来创建该新产品对象。依赖倒置原则告诉我们的要依赖抽象,不要依赖于具体类,简单地说就是让高层组件依赖于低层组件,而且不管高层组合还是低层组件都应该依赖于抽象,而不是具体的实现,在工厂方法模式中,我们可以看到,不管是具体工厂类还是具体产品类都是根据统一的接口(或者抽象)来完成各种不同实现,而且客户端也只需要与相应的抽象类找交道即可。好呢,工厂方法模式的讲解就到这吧,相较而言,工厂方法模式的实现比较简单,我们大家需要理解的是其本质和适应场景。下一篇,我们将继续介绍工厂方式模式的同胞兄弟——抽象工厂方法模式,敬请期待!

前言

在上一篇介绍的工厂方法模式,主要用于创建单个对象,但是如果需要在一个工厂方法中创建一系列相关或者相互依赖的对象时,我们是又该如何应对呢?如果完全按照工厂方法模式来设计,那么在设计的过程中,我们必然会面对越来越多的工厂类,但是由于这些对象彼此间存在一定的关联依赖性,我们或许可以通过机制将这一系列对象的创建工作统一封装起来?这就是即将登场的——抽象工厂方法模式擅长之处呢!

动机

在软件系统中,我们经常面临着一系列相关或者相互依赖的对象的创建工作,又由于需求的多样化,导致在系统的演化过程中,存在越来越多的系列对象的创建工作。这时,常规的对象创建模式已然不能很灵活地处理这种场景,我们需要提供一种更加紧凑的封装机制来规避客户程序与这种多系列对象创建工作的紧耦合。这便是抽象工厂方法模式的由来。

意图

提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类。

结构图

1. 抽象工厂(Abstract Factory)角色:声明一个创建抽象产品对象的操作接口,是抽象工厂方法模式的核心,与业务逻辑无关。

2. 具体工厂(Concrete Factory)角色:创建具体产品对象的操作,含有选择适当的产品对象的逻辑,该逻辑与系统的业务逻辑紧密相关。

3. 抽象产品(Abstract Product)角色:为一类产品对象声明的一个接口,是工厂方法所创建的对象的父类。

4. 具体产品(Concrete Product)角色:实现了AbstractProduct接口的具体产品,也是一个将被相应的具体工厂创建的产品对象,与业务相关。

代码示例

1: public abstract class AbstractProductA{

2: }

3:  

4: public class ProductA1 extends AbstractProductA{

5: public String toString(){

6: return "It is ProductA1";

7: }

8: }

9:  

10: public class ProductA2 extends AbstractProductA{

11: public String toString(){

12: return "It is ProductA2";

13: }

14: }

15:  

16: public abstract class AbstractProductB{

17: }

18:  

19: public class ProductB1 extends AbstractProductB{

20: public String toString(){

21: return "It is ProductB1";

22: }

23: }

24:  

25: public class ProductB2 extends AbstractProductB{

26: public String toString(){

27: return "It is ProductB2";

28: }

29: }

30:  

31: public abstract class AbstractFactory{

32: public abstract AbstractProductA CreateProductA();

33: public abstract AbstractProductB createProductB();

34: }

35:  

36: public class ConcreteFactory1 extends AbstractFactory{

37: public AbstractProductA CreateProductA(){

38: return new ProductA1();

39: }

40: public AbstractProductB createProductB(){

41: return new ProductB1();

42: }

43: }

44:  

45: public class ConcreteFactory2 extends AbstractFactory{

46: public AbstractProductA CreateProductA(){

47: return new ProductA2();

48: }

49: public AbstractProductB createProductB(){

50: return new ProductB2();

51: }

52: }

53:  

54: public class Client{

55: public static void main(String[] args){

56: AbstractFactory cf1=new ConcreteFactory1();

57: AbstractProductA pA=cf1.CreateProductA();

58: AbstractProductB pB=cf1.createProductB();

59: System.out.println(pA);

60: System.out.println(pB);

61:  

62: AbstractFactory cf2=new ConcreteFactory2();

63: AbstractProductA pA2=cf2.CreateProductA();

64: AbstractProductB pB2=cf2.createProductB();

65: System.out.println(pA2);

66: System.out.println(pB2);

67: }

68: }

 从上述示例代码中,我们可以清楚地看到,在一个抽象工厂方法里出现了生成两种不同接口对象的方法,而上一篇介绍的工厂方法通常情况下只会出现生成一种接口对象的方法,这是两者最大的区别。之所以在抽象工厂方法里会出现多个生成不同接口对象的方法,主要是在于这若干个不同接口的对象之间存在一定的关联性,换句话说就是它们从逻辑上来说应该属于同一系列下的不同产品。举个比较形象的比喻就是在安装了win8系统的电脑里,通常只会安装与win8系统兼容的软件,因此这些软件就存在一定的关联性,或者说属于win8这个系列下的不同部分(这个比喻可能有点牵强:)),表达的意思差不多就是这样子吧,下面会有更详细的讲解!

现实场景

上文我们已经谈过了抽象工厂方法模式的基本思想和实现过程,为了更清楚地讲述抽象工厂方法模式的内含,在讲述现实场景之前,首先让我们来进一步学习加深对抽象工厂方法模式的理解吧。通过引进产品族的概念来讲述抽象工厂方法模式,所谓产品族指的位于不同产品等级结构,功能相关联的产品组成的家族,如下面所示:

图中一共有四个产品族,分布三个不同的产品结构中。只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一地确定这个产品。通过产品族的概念来类比抽象工厂方法模式就是一个工厂可以创建出属于不同产品等级结构的一个产品族中的所有对象,如下图所示:

通过上面两个示意图,相信大家对抽象工厂方法模式有了更进一步的理解了吧。说白了,抽象工厂方法模式就是为了创建一系列相关或者相互依赖的对象,而无需指定它们具体的类,个人觉得前半句才是体现其本质的地方,而后半句只是使用接口编程带来的额外效果而已。

前面说了这么多,主要就是为进一步说清抽象工厂方法模式的本质。在现实的软件系统实现中,该模式的使用还是比较常见的。比如,对于游戏软件而言,大多数游戏都有冲关一说,每一关的boss和小兵都不一样,至少攻击力不一样,能量也不一样,它们彼此间的角色关系是不会发生改变的。换句话来说,在游戏中的每一关里,都会出现相应等级、相应能量、相应攻击力的boss和小兵,通常来说,这些角色在每一关特点都会有所不同,抽象到面向对象层面来说,就是这些角色的接口是一样的,但是里面的实现却大不一样,我们需要根据每个关的难易程度来设计实现这些角色。结合我们刚刚所讨论的产品族的概念,就是针对每一关都有相应的一个具体工厂,由其创建每一关所需要的所有角色的具体实现。之所以能够这样实现关键还在于它们角色之间存在一定的关联性,属于同一产品族范畴。针对这样一个场景,运用抽象工厂方法模式来实现并不困难,困难的是如何定义好抽象工厂的接口问题以及扩展问题。说到这些方面也就涉及到了抽象工厂方法模式的适应性呢。后面有介绍。

实现要点

1. 抽象工厂把产品对象的创建工作延迟到具体工厂的子类来完成

2. 没有多系列对象创建需求,就没必要考虑使用抽象工厂方法模式。单个对象或者是没有依赖关系的对象的创建工作完全可以使用简单工厂方法或者工厂方法模式来解决,也完全可以胜任。

3. 所谓的系列对象指的是彼此间有相互依赖,相互作用的关系。

4. 在设计抽象工厂方法接口的过程中,应尽量根据实际需求,将接口定义规范和全面些。因为如果之后再需添加新的各类接口产品,将会不可避免地需要修改抽象工厂方法接口,违背——原则。当然,想要做到这点,首先需求必须明确而且符合抽象工厂方法的适合场景。

5. 在客户端使用时一般是实例化具体的工厂类,由其完成对属于同一产品族的系列对象的创建工作,不同的系列对象的创建工作应该由不由的具体工厂类来完成。

6. 可以将工厂单例化,因为同属于一个产品族的对象只需要一个具体的工厂实例来创建。因此在实际的设计开发中可以考虑将工厂模式实现成单例模式(单例模式的详细讲解之后给出)。

7. 通常抽象工厂方法和工厂方法组合使用来共同应对对象的创建工作。

8. 在具体的工厂类中,来用创建具体产品对象的方法其实完全可以通过上一篇的工厂方法来生成对应的具体方法,但是这样做就会产生很多个工厂类,即使这些产品系列之间的差别很小。

运用效果

1. 分离了具体的类:Abstract Factory模式帮助你控制一个应用创建的对象的类。因为一个工厂封装了创建产品对象的责任和过程,它将客户与类的实现相分离。客户通过产品的抽象接口来操纵实例。产品的类名也在具体工厂的实现中被分离,它们不会出现丰客户代码中。

2. 使得易于交换产品系列:当需要不同产品系列时,只需实例过不同的具体工厂即可产生不同系列的产品对象。

3. 有利于产品的一致性。当一个系列中的产品对象被设计成一起工作时,一个应用一次只能使用同一个系列中的对象,而正是抽象工厂方法模式善长之处。

4. 硬伤)难以支持新种类的产品:因为抽象工厂接口确定了可以被创建的产品集合,支持新种类的产品就需要扩展该工厂接口,这将涉及AbstractFactory类及其具体子类的改变。

适用性

1. 一个系统要独立于它的产品的创建、组合和表示时。

2. 一个系统要由多个产品系列中的一个来配置时。

3. 当你要强调一系列相关的产品对象的设计以便进行联合使用时。

4. 当你提供一个产品类库中,而只想显示它们的接口而不是实现时。

相关模式

1. 抽象工厂模式和工厂方法模式:这两个都模式既有区别,又有联系,可以组合使用。工厂方法一般是针对单独对象的创建工作,而抽象工厂模式注重产品族对象的创建,这是两者主要的区别。如果把抽象工厂创建的产品族简化,这个产品族只有一个产品时,那么抽象工厂与工厂方法是差不多呢,也就是抽象工厂退化成工厂方法,而工厂方法也是可以退化成简单工厂方法,这是它们之间的联系。另外一个就是前文刚刚讲述的可能将工厂方法来提供抽象工厂的具体实现,主要体现在对具体产品的创建工作上,将它们两都组合使用。

2. 抽象工厂和单例模式:前文也已经表达过,就是通常将具体的工厂方法设计成单例,因为创建属于同一产品族的系列对象时,只需要一个具体工厂实例即可。这样就使抽象工厂模式与单例模式组合使用起来。

总结

抽象工厂模式的本质是:选择产品族的实现。定义在抽象工厂里面的方法通常都是有联系的,它们都是产品的某一部分或者是相互依赖的。如果抽象工厂里只有一个产品的创建,那么就退化为工厂方法模式呢。理解了抽象工厂模式,也就理解了OOP的精华:面向接口编程!因为客户在使用抽象工厂来创建具体的产品系列时,是根本不需要知道产品的具体实现细节的,只需要操纵其共有的抽象接口对象即可,实现真正意义上面向接口宗旨!下一篇我们将学习生成器模式!敬请期待!

本文来源:https://www.2haoxitong.net/k/doc/aa0903f0ba0d4a7302763ae8.html

《工厂方法模式 - 创建型模型.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式