一、引言
在上一篇文章中我們講解了過渡的一種模式叫做【簡單工廠】,也有叫【靜态工廠】的,通過對簡單工廠模式得了解,我們也發現了它的缺點,就是随着需求的變化我們要不停地修改工廠裡面的方法的代碼,需求變化越多,裡面的If--Else--也越多,這樣就會造成簡單工廠的實作邏輯過于複雜。設計模式是遵循一定原則而得來的,比如,我們要怎麼增加代碼,怎麼修改代碼,不是想怎麼來就怎麼來的,其中一個原則就是OCP原則,中文是【開放關閉原則】,對增加代碼開發,對修改代碼關閉,是以我們就不能總是這樣修改簡單工廠裡面的方法。本章介紹的工廠方法模式可以解決簡單工廠模式中存在的這個問題,下面就具體看看工廠方法模式是如何解決該問題的。
二、工廠方法模式的胡介紹
2.1、動機(Motivate)
在軟體系統的建構過程中,經常面臨着“某個對象”的建立工作:由于需求的變化,這個對象(的具體實作)經常面臨着劇烈的變化,但是它卻擁有比較穩定的接口。
如何應對這種變化?如何提供一種“封裝機制”來隔離出“這個易變對象”的變化,進而保持系統中“其他依賴對象的對象”不随着需求改變而改變?
2.2、意圖(Intent)
定義一個用于建立對象的接口,讓子類決定執行個體化哪一個類。Factory Method使得一個類的執行個體化延遲到子類。 --《設計模式》GoF
2.3、結構圖(Structure)

2.4、模式的組成
可以看出,在工廠方法模式的結構圖有以下角色:
(1)、抽象工廠角色(Creator): 充當抽象工廠角色,定義工廠類所具有的基本的操作,任何具體工廠都必須繼承該抽象類。
(2)、具體工廠角色(ConcreteCreator):充當具體工廠角色,該類必須繼承抽象工廠角色,實作抽象工廠定義的方法,用來建立具體産品。
(3)、抽象産品角色(Product):充當抽象産品角色,定義了産品類型所有具有的基本操作,具體産品必須繼承該抽象類。
(4)、具體産品角色(ConcreteProduct):充當具體産品角色,實作抽象産品類對定義的抽象方法,由具體工廠類建立,它們之間有一一對應的關系。
2.5、工廠方法模式的代碼實作
【簡單工廠模式】的問題是:如果有新的需求就需要修改工廠類裡面建立産品對象執行個體的那個方法的實作代碼,在面向對象設計一個原則就是哪裡有變化,我就封裝哪裡。還有另外兩個大的原則,其一是:面向抽象程式設計,細節和高層實作都要依賴抽象,第二個原則是:多組合,少繼承。這三個原則是最根本的原則,學習設計模式必須以這三個原則為基點,否則都是枉然。根據這三大原則又衍生出來6個具體的原則,分别是【單一職責原則】,【裡氏替換原則】,【依賴倒置原則】,【接口隔離原則】、【迪米特法則】和【開閉原則】,既然工廠類有變化,我們就封裝它,面向抽象程式設計,我們先抽象出一個工廠基類,然後,每個需求就實作一個具體的工廠類,這樣我們就符合了【開閉原則OCP】,讓一個工廠生産一款産品,并一一對應。我們把具體産品的建立推遲到子類中,此時工廠類(這類是基類了)不再負責所有産品的建立,而隻是給出具體工廠必須實作的接口,這樣工廠方法模式就可以允許系統不修改工廠類邏輯的情況下來添加新産品,這樣也就克服了簡單工廠模式中缺點。下面就是工廠方法模式的實作代碼:
在【工廠方法模式】中,我們同樣也把汽車的類抽象出來一個抽象的基類,這裡正好符合了【面向抽象程式設計】,用戶端在使用的時候不會依賴具體的什麼汽車。使用工廠方法實作的系統,如果系統需要添加新産品時,我們可以利用多态性來完成系統的擴充,對于抽象工廠類和具體工廠中的代碼都不需要做任何改動。例如,我們想增加一輛奔馳車,我們隻需從Car抽象類下繼承一個BenChiCar類,同時在從Factory抽象基類下繼承一個“奔馳”的工廠類BenChinaCarFactory就可以了,這樣擴充符合OCP的原則。具體代碼為:
三、Factory Method模式的幾個要點
Factory Method模式主要用于隔離類對象的使用者和具體類型之間的耦合關系。面對一個經常變化的具體類型,緊耦合關系會導緻軟體的脆弱。
Factory Method模式通過面向對象的手法,将所要建立的具體對象工作延遲到子類,進而實作一種擴充(而非更改)的政策,較好地解決了這種緊耦合關系。
Factory Method模式解決“單個對象”的需求變化;
AbstractFactory模式解決“系列對象”的需求變化;
Builder模式解決“對象部分”的需求變化;
3.1】、工廠方法模式的優點:
(1)、 在工廠方法中,使用者隻需要知道所要産品的具體工廠,無須關系具體的建立過程,甚至不需要具體産品類的類名。
(2)、在系統增加新的産品時,我們隻需要添加一個具體産品類和對應的實作工廠,無需對原工廠進行任何修改,很好地符合了“開閉原則”。
3.2】、工廠方法模式的缺點:
(1)、每次增加一個産品時,都需要增加一個具體類和對象實作工廠,是的系統中類的個數成倍增加,在一定程度上增加了系統的複雜度,同時也增加了系統具體類的依賴。這并不是什麼好事。
3.3】、工廠方法模式使用的場景:
(1)、一個類不知道它所需要的對象的類。在工廠方法模式中,我們不需要具體産品的類名,我們隻需要知道建立它的具體工廠即可。
(2)、一個類通過其子類來指定建立那個對象。在工廠方法模式中,對于抽象工廠類隻需要提供一個建立産品的接口,而由其子類來确定具體要建立的對象,在程式運作時,子類對象将覆寫父類對象,進而使得系統更容易擴充。
(3)、将建立對象的任務委托給多個工廠子類中的某一個,用戶端在使用時可以無須關心是哪一個工廠子類建立産品子類,需要時再動态指定。
四、.NET中實作了工廠方法的類
.NET 類庫中也有很多實作了工廠方法的類,例如Asp.net中,處理程式對象是具體用來處理請求,當我們請求一個*.aspx的檔案時,此時會映射到System.Web.UI.PageHandlerFactory類上進行處理,而對*.ashx的請求将映射到System.Web.UI.SimpleHandlerFactory類中(這兩個類都是繼承于IHttpHandlerFactory接口的),關于這點說明我們可以在“C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\Web.Config”檔案中找到相關定義,具體定義如下:
配置檔案截圖了一部分,有時間大家可以自己去研究一下。
下面我們就具體看下工廠方法模式在Asp.net中是如何實作的,如果對一個Index.aspx頁面送出請求時,将會調用PageHandlerFactory中GetHandler方法來建立一個Index.aspx對象,它們之間的類圖關系如下:
五、總結
每種模式都有自己的使用場合,切記,如果使用錯誤,還不如不用。工廠方法模式通過面向對象程式設計中的多态性來将對象的建立延遲到具體工廠中,進而解決了簡單工廠模式中存在的問題,也很好地符合了開放封閉原則(即對擴充開發,對修改封閉)。
學習設計模式我們一定要謹記設計模式的幾大原則,否則是徒勞無功的。就像學務工一樣,我們要記心法。6大原則就像孤獨求敗的獨孤九劍的劍訣,學會了,變化無窮。