工廠方法模式(Factory Method Pattern)


  • 工廠方法模式概述

工廠方法模式是為了彌補簡單工廠模式的不足並且繼承它的優點而延生出的一種設計模式,屬於GoF中的一種。它能更好的符合開閉原則的要求。

定義:定義了一個用於創建對象的接口,但是讓子類決定將哪一個類實例化。即讓類的實例化延遲到子類


 

舉個例子:大眾汽車公司想必大家都不陌生,它旗下也有不少汽車品牌。大眾汽車公司就好比一個汽車工廠,負責生產和銷售汽車。它可以為客戶提供一個客戶需要的汽車。但是,如果客戶需要的汽車大眾公司目前還沒有,但是公司想要盈利,就必須為此而設計汽車,在這種情況下,大眾公司就要新添加一種汽車,同時要修改公司內部的生產環境(也就是工廠類的代碼)。這就是簡單工廠模式的運行情況。簡單而言,就是工廠類(汽車公司)什么都要干,要修改必須大動干戈。因而一定程度上違背了開閉原則。而工廠方法模式則不一樣,大眾汽車公司不在總公司生產汽車,而是成立分公司,收購別的公司,成立具有針對性的汽車工廠專門生產對應的汽車。若客戶的大量需求得不到滿足,則總公司就另外成立新的二級公司(新品牌汽車的工廠)生產汽車,從而在不修改具體工廠的情況下引進新的產品。正如大眾集團的收購一樣。以下為簡單工廠模式工廠方法模式的區別:

 

  • 工廠方法模式的結構與實現

 

結構:

  1. Product(抽象產品):定義產品的接口,是工廠方法模式所創建對象的公共父類(生產汽車)
  2. ConcreteProduct(具體產品):實現了抽象產品的接口,某類型的具體產品由專門的工廠創建(如具體類型的汽車)
  3. Factory(抽象工廠):它聲明了工廠方法,用於返回一個產品。工廠方法模式的核心,所有創建對象的工廠必須實現該接口(創建生產汽車的工廠)
  4. ConcreteFactory(具體工廠):抽象工廠類的子類,實現了抽象工廠中聲明的工廠方法,返回一個具體產品類的實例(對應具體的某一個汽車工廠)

實現(日志記錄器)

實現:

 1 //Logger.cs  日志記錄器接口 充當抽象產品接口
 2 namespace FactoryMethodSample
 3 {
 4     interface Logger
 5     {
 6         void WriteLog();//抽象產品方法
 7     }
 8 }
 9 
10 //DatabaseLogger 數據庫日志記錄器 具體產品
11 namespace FactoryMethodSample
12 {
13     class DatabaseLogger : Logger
14     {
15         public void WriteLog()
16         {
17         //數據庫日志記錄
18         }
19     }
20 } 
21 
22 //FileLogger 文件日志記錄器 具體產品
23 namespace FactoryMethodSample
24 {
25     class FileLogger : Logger
26     {
27         public void WriteLog()
28         {
29             //文件日志記錄
30         }
31     }
32 }
33 
34 //日志記錄器工廠接口,充當抽象工廠
35 namespace FactoryMethodSample
36 {
37     interface LoggerFactory
38     {
39         Logger CreateLogger();//抽象工廠方法
40     }
41 }
42 //DatabaseLoggerFactory 數據庫日志記錄器工廠類,具體工廠
43 namespace FactoryMethodSample
44 {
45     class DatabaseLoggerFactory : LoggerFactory
46     {
47         public Logger CreateLogger()
48         {
49             //連接數據庫
50             //創建記錄器對象
51             Logger logger = new DatabaseLogger();
52             ...
53             return logger;
54         }
55     }
56 }
57 //FileLoggerFactory 文件日志記錄器工廠類,具體工廠
58 namespace FactoryMethodSample
59 {
60     class FileLoggerFactory : LoggerFactory
61     {
62         public Logger CreateLogger()
63         {
64             //創建文件日志記錄器
65             Logger logger = new FileLogger();
66             ...
67             return logger;
68         }
69     }
70 }
71 //Program 客戶端測試
72 namespace FactoryMethodSample
73 {
74     class Program
75     {
76         
77         static void Main(string [] args)
78         {
79             LoggerFactory factory;//抽象工廠
80             Logger logger;//抽象產品
81             factory = new FileLoggerFactory();//new DatabaseLoggerFactory 可以更換為數據庫日志記錄器
82             logger = factory.CreateLogger();//抽象工廠方法
83             logger.WriteLog();//抽象產品方法
84             ....
85         }
86         //如果要添加新的日志記錄器,只要增加新的具體工廠類,並在客戶端中修改具體工廠的類名便可以,從而避免了對原類的修改
87     }
88 }
  • 工廠方法模式的重載

 在某種情況下,可以用不同的方式來初始化一個產品類,在Logger記錄器中,連接數據庫的操作可以不用在每次CreateLog后再傳入。而是可以將相關參數封裝在一個object中,通過object對象將參數傳入工廠類中,或者在參數列表中給出連接方式來連接數據庫。為此,可以提供一組重載的工廠方法,以不同的方式創建產品。

 

 代碼修改如下:

 1 namespace FactoryMethodSample
 2 {
 3     interface LoggerFactory
 4     {
 5         Logger CreateLogger();//抽象工廠方法
 6         Logger CreateLogger(string args);
 7         Logger CreateLogger(object obj);
 8     }
 9 }
10 
11 //DatabaseLoggerFactory 數據庫日志記錄器工廠類,具體工廠
12 namespace FactoryMethodSample
13 {
14     class DatabaseLoggerFactory : LoggerFactory
15     {
16         public Logger CreateLogger()
17         {
18             //連接數據庫
19             //創建記錄器對象
20             Logger logger = new DatabaseLogger();
21             ...
22             return logger;
23         }
24     }
25     
26     class DatabaseLoggerFactory : LoggerFactory
27     {
28         public Logger CreateLogger(string args)
29         {
30             //用args連接數據庫
31             //
32             Logger logger = new DatabaseLogger();
33             ...
34             return logger;
35         }
36     }
37     
38     class DatabaseLoggerFactory : LoggerFactory
39     {
40         public Logger CreateLogger(object obj)
41         {
42             //將參數封裝在obj中來連接數據庫
43             Logger logger = new DatabaseLogger();
44             ...
45             return logger;
46         }
47     }
48 }
  • 工廠方法模式的隱藏

 在客戶端中,為簡化使用,可以隱藏工廠方法。在工廠類調直接調用產品類的方法,在客戶端中無需用工廠方法創建產品對象,直接使用工廠對象即可調用所創建的產品對象中的業務方法

代碼修改如下:

 1 //LoggerFactory 修改
 2 abstract class LoggerFactory//改接口為抽象類
 3 {
 4     public void WriteLog()//工廠類直接調用日志記錄器的WriteLog();
 5     {
 6         Logger logger = this.CreateLogger();
 7         logger.WriteLog();
 8     }
 9     public abstract Logger CreateLogger();
10 }
11 
12 //客戶端修改如下
13 namespace FactoryMethodSample
14 {
15     class Program
16     {
17         static void Main(string [] args)
18         {
19             LoggerFactory factory;
20             //Load configuration file;
21             string factoryString = ConfigurationManager.AppSettings["factory"];
22             //反射生成對象
23             factory = (LoggerFactory)Assembly.Load("FactoryMethodSample").CreateInstance(factoryString);
24             factory.WriteLog();//直接使用工廠對象調用產品對象的業務方法
25         }
26     }
27 }

 

  • 工廠方法模式的優缺點和適用環境

  (1)工廠方法模式的優點

    (1)用戶只需要關心產品對應的工廠,甚至無需關心創建細節或具體產品類的類名  
    (2)基於工廠角色和產品的多態性設計是工廠模式的關鍵。它能自主決定如何創建哪種產品對象,而創建細節都封裝在具體工廠內部
    (3)在系統要添加新的產品時,無需修改抽象工廠和抽象產品提供的接口,無需修改客戶端,也無需修改其他的具體工廠和具體產品,只要添加一個具體工廠和具體產品即可,從而提高系統的可擴展性(符合開閉原則)  

  (2)工廠方法模式的缺點

    (1)在添加新產品時,要編寫新的具體產品類,並要提供與之對應的具體工廠類。系統軟件個數也成對增加,從而增加了系統的復雜度,帶來更多開銷
    (2)由於系統的可擴展性,在客戶端中要引入抽象層進行定義,從而增加了系統的抽象性和理解難度

  (3)工廠方法模式的適用環境

    (1)客戶端不需要知道它需要的對象的類。只需知道對應的工廠即可

    (2)抽象工廠類通過子類來指定創建那哪個對象。即抽象工廠類只需要提供一個創建產品的接口,而由其子類確定具體要創建的對象,利用多態性和里氏代換原則,子類對象將覆蓋父類對象,從而使系統更容易擴展 


 

  •  在日志記錄器實例中,在更換日志記錄器時需要修改客戶端代碼。為了按照開閉原則的要求執行,可以在不修改任何客戶端代碼的基礎上更換或增加新的日志記錄方式。即通過配置文件程序集的反射機制,讀取配置文件中存儲的類名字符串生成對象。這里沒有進行講解,可以自行搜索..~_~!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM