工廠方法模式是爲了彌補簡單工廠模式的不足而且繼承它的優勢而延生出的一種設計模式,屬於GoF中的一種。它能更好的符合開閉原則的要求。html
定義:定義了一個用於建立對象的接口,可是讓子類決定將哪個類實例化。即讓類的實例化延遲到子類數據庫
舉個例子:大衆汽車公司想必你們都不陌生,它旗下也有很多汽車品牌。大衆汽車公司就比如一個汽車工廠,負責生產和銷售汽車。它能夠爲客戶提供一個客戶須要的汽車。可是,若是客戶須要的汽車大衆公司目前尚未,可是公司想要盈利,就必須爲此而設計汽車,在這種狀況下,大衆公司就要新添加一種汽車,同時要修改公司內部的生產環境(也就是工廠類的代碼)。這就是簡單工廠模式的運行狀況。簡單而言,就是工廠類(汽車公司)什麼都要幹,要修改必須大動干戈。於是必定程度上違背了開閉原則。而工廠方法模式則不同,大衆汽車公司不在總公司生產汽車,而是成立分公司,收購別的公司,成立具備針對性的汽車工廠專門生產對應的汽車。若客戶的大量需求得不到知足,則總公司就另外成立新的二級公司(新品牌汽車的工廠)生產汽車,從而在不修改具體工廠的狀況下引進新的產品。正如大衆集團的收購同樣。如下爲簡單工廠模式和工廠方法模式的區別:設計模式
結構:測試
實現:(日誌記錄器)this
實現:spa
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對象將參數傳入工廠類中,或者在參數列表中給出鏈接方式來鏈接數據庫。爲此,能夠提供一組重載的工廠方法,以不一樣的方式建立產品。設計
代碼修改以下:3d
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 }
在客戶端中,爲簡化使用,能夠隱藏工廠方法。在工廠類調直接調用產品類的方法,在客戶端中無需用工廠方法建立產品對象,直接使用工廠對象便可調用所建立的產品對象中的業務方法日誌
代碼修改以下:code
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)抽象工廠類經過子類來指定建立那哪一個對象。即抽象工廠類只須要提供一個建立產品的接口,而由其子類肯定具體要建立的對象,利用多態性和里氏代換原則,子類對象將覆蓋父類對象,從而使系統更容易擴展