工厂方法模式——创建型模型(1)

前言

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

动机

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

意图

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

结构图

image

  1. 抽象工厂(creator)角色:是工厂方法模式的核心,任何通过该模式创建对象的具体工厂类都须实现该接口
  2. 具体工厂(ConcreteCreator)角色:实现了抽象工厂类的具体工厂类,包含与应用程序相关的逻辑,被客户端调用以生成具体的产品对象。在上图中类BMWCreator和BENZCreator就是两个具体的工厂实现类,用于创建不同实现的Car对象
  3. 抽象产品(Product)角色:工厂方法所创建的对象的父类型,也就是具体产品对象的共同父类或者说是共同拥有的接口。在上图中,这个角色为Car
  4. 具体产品(ConcreteProduct)角色:实现了抽象产品接口的产品。每个具体产品与创建自己的具体工厂是一般来说是一一对应。上图中,BMW和BENZ就是两个具体的具体产品类

代码示例

 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:   
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. 程杰著《大话设计模式》一书
  2. 陈臣等著《研磨设计模式》一书
  3. GOF著《设计模式》一书
  4. Terrylee .Net设计模式系列文章
  5. 吕震宇老师 设计模式系列文章

 

 

 

 

 

posted @ 2012-09-16 20:30  JackyBing  阅读(1279)  评论(6编辑  收藏  举报