工廠方法模式概述 工廠方法模式是為了彌補簡單工廠模式的不足並且繼承它的優點而延生出的一種設計模式,屬於GoF中的一種。它能更好的符合開閉原則的要求。 舉個例子:大眾汽車公司想必大家都不陌生,它旗下也有不少汽車品牌。大眾汽車公司就好比一個汽車工廠,負責生產和銷售汽車。它可以為客戶提供一個客戶需要的汽車 ...
- 工廠方法模式概述
工廠方法模式是為了彌補簡單工廠模式的不足並且繼承它的優點而延生出的一種設計模式,屬於GoF中的一種。它能更好的符合開閉原則的要求。
舉個例子:大眾汽車公司想必大家都不陌生,它旗下也有不少汽車品牌。大眾汽車公司就好比一個汽車工廠,負責生產和銷售汽車。它可以為客戶提供一個客戶需要的汽車。但是,如果客戶需要的汽車大眾公司目前還沒有,但是公司想要盈利,就必須為此而設計汽車,在這種情況下,大眾公司就要新添加一種汽車,同時要修改公司內部的生產環境(也就是工廠類的代碼)。這就是簡單工廠模式的運行情況。簡單而言,就是工廠類(汽車公司)什麼都要乾,要修改必須大動干戈。因而一定程度上違背了開閉原則。而工廠方法模式則不一樣,大眾汽車公司不在總公司生產汽車,而是成立分公司,收購別的公司,成立具有針對性的汽車工廠專門生產對應的汽車。若客戶的大量需求得不到滿足,則總公司就另外成立新的二級公司(新品牌汽車的工廠)生產汽車,從而在不修改具體工廠的情況下引進新的產品。正如大眾集團的收購一樣。以下為簡單工廠模式和工廠方法模式的區別:
- 工廠方法模式的結構與實現
結構:
- Product(抽象產品):定義產品的介面,是工廠方法模式所創建對象的公共父類(生產汽車)
- ConcreteProduct(具體產品):實現了抽象產品的介面,某類型的具體產品由專門的工廠創建(如具體類型的汽車)
- Factory(抽象工廠):它聲明瞭工廠方法,用於返回一個產品。工廠方法模式的核心,所有創建對象的工廠必須實現該介面(創建生產汽車的工廠)
- 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)抽象工廠類通過子類來指定創建那哪個對象。即抽象工廠類只需要提供一個創建產品的介面,而由其子類確定具體要創建的對象,利用多態性和里氏代換原則,子類對象將覆蓋父類對象,從而使系統更容易擴展
- 在日誌記錄器實例中,在更換日誌記錄器時需要修改客戶端代碼。為了按照開閉原則的要求執行,可以在不修改任何客戶端代碼的基礎上更換或增加新的日誌記錄方式。即通過配置文件和程式集的反射機制,讀取配置文件中存儲的類名字元串生成對象。這裡沒有進行講解,可以自行搜索..~_~!!