C#设计模式01-工厂方法模式(附源码)

     在简单工厂模式中,工厂类负责创建所有产品的实例,这导致工厂类的职责太重,并且一旦工厂类无法正常工作,整个系统将会受到极大的影响,而且简单工厂模式并不能很好的符合开闭原则。为了解决简单工厂模式的这些缺点,工厂方法模式诞生了。

       工厂方法模式保证我们在增加新的具体产品时,不需要对现有的系统做任何修改!

       工厂方法模式定义

       定义一个用于创建对象的接口,但是由子类来决定实例化哪一个类。工厂方法模式将一个类的实例化延迟到子类。

       为了避免工厂类职责过重,工厂方法模式里面的工厂只负责生产一种具体产品!

       汽车是我们生活中最常见的,考虑这样一个情景。宝马公司(BaoMaFactory)能生产宝马汽车(BaoMa),大众公司(DaZhongFactory)能生产大众汽车(DaZhong)。宝马公司,大众公司这些工厂可以抽象出一个共同的父类,他们都是工厂(AbstractCarFactory)。他们所生产的的汽车也可以抽象出一个父类,即他们都是汽车(AbstractCar)。下面我们就用这个例子来说明一下工厂方法模式的UML图:

C#设计模式01-工厂方法模式(附源码)_第1张图片

        从UML图中大家应该看到了一点,如果这个时候我要新增一个丰田公司和丰田汽车,只需新增一个FengTianFactory类和FengTian类,不需要对以前的代码进行修改。

       可以看得出来,父类AbstractCarFactory将不负责创建具体产品,而是将具体产品的创建工作交给子类(DaZhongFactory,BaoMaFactory)去做。也就是将产品的创建延迟到工厂子类去完成。

       接下来说明工厂方法模式中的四种角色

      (1)抽象工厂(AbstractCarFactory):声明创建产品的接口。客户端针对这个接口编程。

      (2)实体工厂(BaoMaFactory,DaZhongFactory):它们是抽象工厂的子类,负责实现抽象工厂里面创建产品的方法(CreateCar)。

      (3)抽象产品(AbstractCar):它是所有具体产品的父类,声明具体产品的公共方法,客户端针对这个接口编程。

      (4)具体产品(BaoMa,DaZhong):它是抽象产品的子类,负责实现抽象产品中声明的方法(Run方法)。

      最后分别把这四种角色的代码实现写出来:

         抽象工厂(AbstractCarFactory)的代码如下:

[csharp] view plain copy print ?
  1. namespace 工厂方法模式  
  2. {  
  3.     interface AbstractCarFactory//汽车厂父类  
  4.     {  
  5.         AbstractCar CreateCar();//创建汽车(注意返回类型是AbstractCar)  
  6.     }  
  7. }  
        实体工厂( BaoMaFactory,DaZhongFactory)的代码如下:
[csharp] view plain copy print ?
  1. namespace 工厂方法模式  
  2. {  
  3.     class BaoMaFactory:AbstractCarFactory//宝马汽车厂  
  4.     {  
  5.         public AbstractCar CreateCar()  
  6.         {  
  7.             Console.WriteLine("创建了宝马车!");  
  8.             return new BaoMa();  
  9.         }  
  10.     }  
  11. }  
[csharp] view plain copy print ?
  1. namespace 工厂方法模式  
  2. {  
  3.     class DaZhongFactory:AbstractCarFactory//大众汽车厂  
  4.     {  
  5.         public AbstractCar CreateCar()  
  6.         {  
  7.             Console.WriteLine("创建了大众车!");  
  8.             return new DaZhong();  
  9.         }  
  10.     }  
  11. }  
        抽象产品(AbstractCar)的代码如下:

[csharp] view plain copy print ?
  1. namespace 工厂方法模式  
  2. {  
  3.     interface AbstractCar//抽象汽车  
  4.     {  
  5.         void Run();//汽车行驶方法  
  6.     }  
  7. }  
        具体产品(BaoMa,DaZhong)的代码如下:

[csharp] view plain copy print ?
  1. namespace 工厂方法模式  
  2. {  
  3.     class BaoMa:AbstractCar//宝马汽车  
  4.     {  
  5.         public void Run()  
  6.         {  
  7.             Console.WriteLine("被创建的宝马车跑起来啦!");  
  8.         }  
  9.     }  
  10. }  
[csharp] view plain copy print ?
  1. namespace 工厂方法模式  
  2. {  
  3.     class DaZhong:AbstractCar//大众汽车  
  4.     {  
  5.         public void Run()  
  6.         {  
  7.             Console.WriteLine("被创建的大众车跑起来啦!");  
  8.         }  
  9.     }  
  10. }  
         客户端代码如下:
[csharp] view plain copy print ?
  1. namespace 工厂方法模式  
  2. {  
  3.     class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.             AbstractCar car;  
  8.             AbstractCarFactory carFactory = new BaoMaFactory();//这里可以通过配置文件+反射机制实现。  
  9.             car=carFactory.CreatCar();  
  10.             car.Run();  
  11.             Console.ReadLine();  
  12.         }  
  13.     }  
  14. }  

        程序的最终运行结果如下:

C#设计模式01-工厂方法模式(附源码)_第2张图片


        在上面的客户端代码中,我们直接new了一个BaoMaFactory工厂,如果要换成大众汽车厂就必须修改客户端代码。这违背了开闭原则。所以现在通过把工厂保存在配置文件中,在客户端通过反射机制动态获取工厂。这样可以在不修改源代码的前提下,自由更换工厂。

        所以优化后的客户端代码如下:

[csharp] view plain copy print ?
  1. namespace 工厂方法模式  
  2. {  
  3.     class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.             AbstractCar car;  
  8.             //从配置文件获取具体工厂名称(这里是宝马工厂)  
  9.             string factoryFactoryName = ConfigurationManager.AppSettings["factory"];  
  10.             //通过反射创建工厂类的实例  
  11.             AbstractCarFactory carFactory = Assembly.Load("工厂方法模式").CreateInstance(factoryFactoryName)   
  12.             as  AbstractCarFactory ;  
  13.             car = carFactory.CreatCar();  
  14.             car.Run();  
  15.             Console.ReadLine();  
  16.         }  
  17.     }  
  18. }  

        配置文件的代码如下:

  
    
  
       但是由于每一种具体产品都有一个对应的具体工厂。所以新增具体产品类的时候会导致系统中类的个数成对增加,在一定程度上增加了系统的复杂度,因为有了更多的类需要编译和运行。如果系统中产品类很多这会导致类泛滥,所以工厂方法在使用时,要根据具体情况来决定。

           源码下载地址:http://pan.baidu.com/s/1kUgSGQj 密码:573g

        下一篇中讲给大家讲解抽象工厂模式。

你可能感兴趣的:(C#设计模式)