1. 程式人生 > >C#設計模式01-工廠方法模式(附原始碼)

C#設計模式01-工廠方法模式(附原始碼)

     在簡單工廠模式中,工廠類負責建立所有產品的例項,這導致工廠類的職責太重,並且一旦工廠類無法正常工作,整個系統將會受到極大的影響,而且簡單工廠模式並不能很好的符合開閉原則。為了解決簡單工廠模式的這些缺點,工廠方法模式誕生了。

       工廠方法模式保證我們在增加新的具體產品時,不需要對現有的系統做任何修改!

       工廠方法模式定義

       定義一個用於建立物件的介面,但是由子類來決定例項化哪一個類。工廠方法模式將一個類的例項化延遲到子類。

       為了避免工廠類職責過重,工廠方法模式裡面的工廠只負責生產一種具體產品!

       汽車是我們生活中最常見的,考慮這樣一個情景。寶馬公司(BaoMaFactory)能生產寶馬汽車(BaoMa),大眾公司(DaZhongFactory)能生產大眾汽車(DaZhong)。寶馬公司,大眾公司這些工廠可以抽象出一個共同的父類,他們都是工廠(AbstractCarFactory)。他們所生產的的汽車也可以抽象出一個父類,即他們都是汽車(AbstractCar)。下面我們就用這個例子來說明一下工廠方法模式的UML圖:

        從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. }  

        程式的最終執行結果如下:


        在上面的客戶端程式碼中,我們直接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. }  

        配置檔案的程式碼如下:

  <appSettings>
    <add key="factory" value="工廠方法模式.BaoMaFactory"/>
  </appSettings>
       但是由於每一種具體產品都有一個對應的具體工廠。所以新增具體產品類的時候會導致系統中類的個數成對增加,在一定程度上增加了系統的複雜度,因為有了更多的類需要編譯和執行。如果系統中產品類很多這會導致類氾濫,所以工廠方法在使用時,要根據具體情況來決定。

           原始碼下載地址:http://pan.baidu.com/s/1kUgSGQj 密碼:573g

        下一篇中講給大家講解抽象工廠模式。