FactoryMethod 工厂方法模式

来源:互联网 发布:oracle查看数据库状态 编辑:程序博客网 时间:2024/05/16 06:58

工厂方法(FactoryMethod)模式是类的创建模式,其用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。

工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。

在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不接触哪一个产品类被实例化这种细节。这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。

在Factory Method模式中,工厂类与产品类往往具有平行的等级结构,它们之间一一对应。

二、 Factory Method模式角色与结构:

 

抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。

具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:BulbCreator与TubeCreator。

抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在上图中,这个角色是Light。

具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。

三、 程序举例:对于工厂模式来说,要求高层模块变化相对较慢,底层模块变化相对较快。这样符合设计模式中的依赖倒置原则——高层模块不依赖于底层模块。换句话说,软件设计是要划分易变部分和稳定部分。 
      刚开始接触设计模式时就常常听到同事提起工厂模式,那时也看过一些人写的Blog,但是往往把注意力放在代码的编写上。在这段时间的学习中慢慢体会到设计模式是用来解决一类问题,而不是某些固定的代码片段。换句话说是解决问题的思想。设计模式可以解决模块的耦合关系,可以解决因需求变动带来的问题。程序在第一次编写时,各个模块之间可能是紧耦合,但是经过代码重构,可以将模块之间变为松耦合。当然,我觉得我们也可以在软件设计之初把变化考虑到其中,对于业务型软件设计,在了解需求后,可以尽可能将其分出主次关系。也就是主体与枝节的关系。如下图 
       对于工厂模式来说,要求高层模块变化相对较慢,底层模块变化相对较快。这样符合设计模式中的依赖倒置原则——高层模块不依赖于底层模块。换句话说,软件设计是要划分易变部分和稳定部分。这样在一些枝节问题发生变化时,主干不用变化。如果是紧耦合状态,有可能造成一个地方变化,连带着很多地方要发生变化。
       工厂模式要解决的是“某个对象”的创建工作,由于需求的变化,这个对象常常面临着剧烈的变化,但是这个对象拥有的接口相对稳定。也就是说:枝节常常发生变化,但是枝节与主干的接口相对稳定。
       《设计模式》中是这样说明:定义一个用于创建对象的接口,让子类决定实例化那个类。FactoryMethod使得一个类的实例化延迟到子类。
       现在看这句话可能有些不明白,我们一会再来分析一下。先来看看工厂模式的大体结构。如下图:
  工厂方法模式UML图工厂方法模式UML图
 
       我们还是用实例化汽车的例子来解释。对于客户端程序(ClientApp)如果想要一个汽车的对象,需要调用生产这个汽车的Factory的对象。当然,这个类继承自一个AbstractFactory基类。而这个Factory类就是《设计模式》中提到的“子类”,它来决定实例化那个类。
       下面我们来具体实现一下代码,首先,我们需要两个基类,一个是Car的,一个是Factory的。Factory类型的作用是构建Car的对象。代码如下:
[c-sharp] view plaincopy
  1. public abstract class AbstractCar  
  2.     {  
  3.         public abstract string Run();  
  4.         public abstract string Stop();  
  5.         public abstract string Accelerate();  
  6.         public abstract string Decelerate();  
  7.     }  
  8.    
  9.     public abstract class AbstractFactory  
  10.     {  
  11.         public abstract AbstractCar CreateCar();  
  12.     }  
  13.     下面,我们来做一个BMW的实现代码:  
  14. public class BMWCar:AbstractCar  
  15.     {  
  16.         public override string Run()  
  17.         {  
  18.             return "BMW Run";  
  19.         }  
  20.    
  21.         public override string Stop()  
  22.         {  
  23.             return "BMW Stop";  
  24.         }  
  25.    
  26.         public override string Accelerate()  
  27.         {  
  28.             return "BMW Accelerate";  
  29.         }  
  30.    
  31.         public override string Decelerate()  
  32.         {  
  33.             return "BMW Decalerate";  
  34.         }  
  35.     }  
  36.    
  37.     public class BMWFactory:AbstractFactory  
  38.     {  
  39.         public override AbstractCar CreateCar()  
  40.         {  
  41.             return new BMWCar();  
  42.         }  
  43.     }  
  44. 这样我们就可以在客户端程序得到一个BMW的实例,并使用它的方法:  
  45. class Class1  
  46.     {  
  47.         /// <summary>  
  48.         /// 应用程序的主入口点。  
  49.         /// </summary>  
  50.         [STAThread]  
  51.         static void Main(string[] args)  
  52.         {  
  53.             AbstractCar car = CreateCarFunc(new BMWFactory ());  
  54.             Console.Write(car.Run() + "/n");  
  55.             Console.Write(car.Stop() + "/n");  
  56.             Console.Write(car.Accelerate() + "/n");  
  57.             Console.Write(car.Decelerate() + "/n");  
  58.             Console.Read();  
  59.         }  
  60.    
  61.         public static AbstractCar CreateCarFunc(AbstractFactory factory)  
  62.         {  
  63.             return factory.CreateCar();  
  64.         }  
  65. }  
  66. 在客户端程序中,我们AbstractFactory的对象来得到Car的对象  
  67. 结果如下:  
  68. BMW Run  
  69. BMW Stop  
  70. BMW Accelerate  
  71. BMW Decalerate  
  72. 如果我们需求变了,现在要BORA的对象,那末,我们首先要对程序作一下扩展,先加入BOAR的Car类和Factory类,代码如下:  
  73. public class BORACar:AbstractCar  
  74.     {  
  75.         public override string Run()  
  76.         {  
  77.             return "BORA Run";  
  78.         }  
  79.    
  80.         public override string Stop()  
  81.         {  
  82.             return "BORA Stop";  
  83.         }  
  84.    
  85.         public override string Accelerate()  
  86.         {  
  87.             return "BORA Accelerate";  
  88.         }  
  89.    
  90.         public override string Decelerate()  
  91.         {  
  92.             return "BORA Decelerate";  
  93.         }  
  94.     }  
  95.    
  96.     public class BORAFactory:AbstractFactory  
  97.     {  
  98.         public override AbstractCar CreateCar()  
  99.         {  
  100.             return new BORACar();  
  101.         }  
  102. }  
  103. 在客户端程序中,我们只要稍作修改,将BMWFactory的实例化变为BORAFactory的实例化就可以,代码如下:  
  104. class Class1  
  105.     {  
  106.         /// <summary>  
  107.         /// 应用程序的主入口点。  
  108.         /// </summary>  
  109.         [STAThread]  
  110.         static void Main(string[] args)  
  111.         {  
  112.             AbstractCar car = CreateCarFunc(new BORAFactory());  
  113.             Console.Write(car.Run() + "/n");  
  114.             Console.Write(car.Stop() + "/n");  
  115.             Console.Write(car.Accelerate() + "/n");  
  116.             Console.Write(car.Decelerate() + "/n");  
  117.             Console.Read();  
  118.         }  
  119.    
  120.         public static AbstractCar CreateCarFunc(AbstractFactory factory)  
  121.         {  
  122.             return factory.CreateCar();  
  123.         }  
  124. }  
得到的结果是:
BORA Run
BORA Stop
BORA Accelerate
BORA Decelerate
Factory Method的几个要点:
1、Factory Method模式主要用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。
2、Factory Method模式通过面向对象的手法,将所要创建的对象工作延迟到子类,从而实现一种扩展的策略,较好的解决了这种紧耦合关系。

工厂方法的活动序列图

 

活动过程包括:

客户端创建BulbCreator对象,客户端持有此对象的类型是Creator,而实际类型是BulbCreator。然后客户端调用BulbCreator的factory方法,之后BulbCreator调用BulbLight的构造函数创造出产品BulbLight对象。


四、 工厂方法模式与简单工厂模式

工厂方法模式与简单工厂模式再结构上的不同不是很明显。工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。

工厂方法模式之所以有一个别名叫多态性工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。

当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了"开放-封闭"原则。而简单工厂模式在添加新产品对象后不得不修改工厂方法,扩展性不好。

工厂方法模式退化后可以演变成简单工厂模式。

五、 Factory Method模式演化

使用接口或抽象类
抽象工厂角色和抽象场频角色都可以选择由接口或抽象类实现。

使用多个工厂方法
抽象工厂角色可以规定出多于一个的工厂方法,从而使具体工厂角色实现这些不同的工厂方法,这些方法可以提供不同的商业逻辑,以满足提供不同的产品对象的任务。

产品的循环使用
工厂方法总是调用产品类的构造函数以创建一个新的产品实例,然后将这个实例提供给客户端。而在实际情形中,工厂方法所做的事情可以相当复杂。

一个常见的复杂逻辑就是循环使用产品对象。工厂对象将已经创建过的产品登记到一个聚集中,然后根据客户所请求的产品状态,向聚集查询。如果有满足要求的产品对象,就直接将产品返回客户端;如果聚集中没有这样的产品对象,那么就创建一个新的满足要求的产品对象,然后将这个对象登记到聚集中,再返还给客户端。"享元模式(Flyweight Pattern)"就是这样一个模式。

 

多态性的丧失和模式的退化
一个工厂方法模式的实现依赖于工厂角色和产品角色的多态性。在有些情况下,这个模式可以出现退化。

工厂方法返回的类型应当是抽象类型,而不是具体类型。调用工厂方法的客户端应当依赖抽象产品编程,而不是具体产品。如果工厂仅仅返回一个具体产品对象,便违背了工厂方法的用意,发生退化,这时就不再是工厂模式了。

工厂的等级结构:工厂对象应当有一个抽象的超类型。如果等级结构中只有一个具体工厂类的话,抽象工厂就可以省略,发生了退化。

六、 Factory Method模式与其它模式的关系

与工厂方法模式有关的模式还包括:
模板方法模式、MVC模式、享元模式、备忘录模式