c++工廠模式和c++工廠方法
問題描述
http://www.jellythink.com/archives/category/columns
之前講到了C++設計模式——簡單工廠模式,由於簡單工廠模式的侷限性,比如:工廠現在能生產ProductA、ProductB和ProductC三種產品了,此時,需要增加生產ProductD產品;那麼,首先是不是需要在產品列舉型別中新增新的產品型別標識,然後,修改Factory類中的switch結構程式碼。是的,這種對程式碼的修改,對原有程式碼的改動量較大,易產生編碼上的錯誤(雖然很簡單,如果工程大了,出錯也是在所難免的!!!)。這種對程式碼的修改是最原始,最野蠻的修改,本質上不能稱之為對程式碼的擴充套件。同時,由於對已經存在的函式進行了修改,那麼以前進行過的測試,都將是無效的,所有的測試,都將需要重新進行,所有的程式碼都需要進行重新覆蓋。這種,增加成本,不能提高效率的事情,在公司是絕對不允許的(除非昏庸的PM)。出於種種原因,簡單工廠模式,在實際專案中使用的較少。那麼該怎麼辦?怎麼辦呢?需要對原有程式碼影響降到最小,同時能對原有功能進行擴充套件。
UML類圖
那麼今天介紹的工廠方法模式,就隆重登場了。它只是對簡單工廠模式的擴充套件,在GOF的介紹中,它們是合併在一起的,而我則是單獨分開進行講解的,就是為了區分二者的利弊,便於大家在實際專案中進行更好的把握與應用。工廠方法模式是在簡單工廠模式的基礎上,對“工廠”添加了一個抽象層。將工廠共同的動作抽象出來,作為抽象類,而具體的行為由子類本身去實現,讓子類去決定生產什麼樣的產品。
如圖,FactoryA專心負責生產ProductA,FactoryB專心負責生產ProductB,FactoryA和FactoryB之間沒有關係;如果到了後期,如果需要生產ProductC時,我們則可以建立一個FactoryC工廠類,該類專心負責生產ProductC類產品。由於FactoryA、FactoryB和FactoryC之間沒有關係,當加入FactoryC加入時,對FactoryA和FactoryB的工作沒有產生任何影響,那麼對程式碼進行測試時,只需要單獨對FactoryC和ProductC進行單元測試,而FactoryA和FactoryB則不用進行測試,則可省去大量無趣無味的測試工作。
適用場合
工廠方法模式的意義是定義一個建立產品物件的工廠介面,將實際建立工作推遲到子類當中。核心工廠類不再負責產品的建立,這樣核心類成為一個抽象工廠角色,僅負責具體工廠子類必須實現的介面,這樣進一步抽象化的好處是使得工廠方法模式可以使系統在不修改具體工廠角色的情況下引進新的產品。
- 在設計的初期,就考慮到產品在後期會進行擴充套件的情況下,可以使用工廠方法模式;
- 產品結構較複雜的情況下,可以使用工廠方法模式;
由於使用設計模式是在詳細設計時,就需要進行定奪的,所以,需要權衡多方面的因素,而不能為了使用設計模式而使用設計模式。
程式碼實現
問題描述
之前講到了C++設計模式——簡單工廠模式,由於簡單工廠模式的侷限性,比如:工廠現在能生產ProductA、ProductB和ProductC三種產品了,此時,需要增加生產ProductD產品;那麼,首先是不是需要在產品列舉型別中新增新的產品型別標識,然後,修改Factory類中的switch結構程式碼。是的,這種對程式碼的修改,對原有程式碼的改動量較大,易產生編碼上的錯誤(雖然很簡單,如果工程大了,出錯也是在所難免的!!!)。這種對程式碼的修改是最原始,最野蠻的修改,本質上不能稱之為對程式碼的擴充套件。同時,由於對已經存在的函式進行了修改,那麼以前進行過的測試,都將是無效的,所有的測試,都將需要重新進行,所有的程式碼都需要進行重新覆蓋。這種,增加成本,不能提高效率的事情,在公司是絕對不允許的(除非昏庸的PM)。出於種種原因,簡單工廠模式,在實際專案中使用的較少。那麼該怎麼辦?怎麼辦呢?需要對原有程式碼影響降到最小,同時能對原有功能進行擴充套件。
UML類圖
那麼今天介紹的工廠方法模式,就隆重登場了。它只是對簡單工廠模式的擴充套件,在GOF的介紹中,它們是合併在一起的,而我則是單獨分開進行講解的,就是為了區分二者的利弊,便於大家在實際專案中進行更好的把握與應用。工廠方法模式是在簡單工廠模式的基礎上,對“工廠”添加了一個抽象層。將工廠共同的動作抽象出來,作為抽象類,而具體的行為由子類本身去實現,讓子類去決定生產什麼樣的產品。
如圖,FactoryA專心負責生產ProductA,FactoryB專心負責生產ProductB,FactoryA和FactoryB之間沒有關係;如果到了後期,如果需要生產ProductC時,我們則可以建立一個FactoryC工廠類,該類專心負責生產ProductC類產品。由於FactoryA、FactoryB和FactoryC之間沒有關係,當加入FactoryC加入時,對FactoryA和FactoryB的工作沒有產生任何影響,那麼對程式碼進行測試時,只需要單獨對FactoryC和ProductC進行單元測試,而FactoryA和FactoryB則不用進行測試,則可省去大量無趣無味的測試工作。
適用場合
工廠方法模式的意義是定義一個建立產品物件的工廠介面,將實際建立工作推遲到子類當中。核心工廠類不再負責產品的建立,這樣核心類成為一個抽象工廠角色,僅負責具體工廠子類必須實現的介面,這樣進一步抽象化的好處是使得工廠方法模式可以使系統在不修改具體工廠角色的情況下引進新的產品。
- 在設計的初期,就考慮到產品在後期會進行擴充套件的情況下,可以使用工廠方法模式;
- 產品結構較複雜的情況下,可以使用工廠方法模式;
由於使用設計模式是在詳細設計時,就需要進行定奪的,所以,需要權衡多方面的因素,而不能為了使用設計模式而使用設計模式。
程式碼實現
問題描述
之前講到了C++設計模式——工廠方法模式,我們可能會想到,後期產品會越來越多了,建立的工廠也會越來越多,工廠進行了增長,工廠變的凌亂而難於管理;由於工廠方法模式建立的物件都是繼承於Product的,所以工廠方法模式中,每個工廠只能建立單一種類的產品,當需要生產一種全新的產品(不繼承自Product)時,發現工廠方法是心有餘而力不足。
舉個例子來說:一個顯示器電路板廠商,旗下的顯示器電路板種類有非液晶的和液晶的;這個時候,廠商建造兩個工廠,工廠A負責生產非液晶顯示器電路板,工廠B負責生產液晶顯示器電路板;工廠一直就這樣執行著。有一天,總經理髮現,直接生產顯示器的其餘部分也挺掙錢,所以,總經理決定,再建立兩個工廠C和D;C負責生產非液晶顯示器的其餘部件,D負責生產液晶顯示器的其餘部件。此時,旁邊參謀的人就說了,經理,這樣做不好,我們可以直接在工廠A中新增一條負責生產非液晶顯示器的其餘部件的生產線,在工廠B中新增一條生產液晶顯示器的其餘部件的生產線,這樣就可以不用增加廠房,只用將現有廠房進行擴大一下,同時也方便工廠的管理,而且生產非液晶顯示器電路板的技術人員對非液晶顯示的其餘部件的生產具有指導的作用,生產液晶顯示器電路板也是同理。總經理髮現這是一個不錯的主意。
再回到軟體開發的過程中來,工廠A和B就是之前所說的C++設計模式——工廠方法模式;總經理再次建立工廠C和D,就是重複C++設計模式——工廠方法模式,只是生產的產品不同罷了。這樣做的弊端就如參謀所說的那樣,增加了管理成本和人力成本。在面向物件開發的過程中,是很注重物件管理和維護的,物件越多,就越難進行管理和維護;如果工廠數量過多,那麼管理和維護的成本將大大增加;雖然生產的是不同的產品,但是可以二者之間是有微妙的關係的,如參謀所說,技術人員的一些技術經驗是可以借鑑的,這就相當於同一個類中的不同物件,之間是可以公用某些資源的。那麼,增加一條流水線,擴大廠房,當然是最好的主意了。
實際問題已經得到了解決,那麼如何使用設計模式模擬這個實際的問題呢?那就是接下來所說的抽象工廠模式。
UML類圖
現在要講的抽象工廠模式,就是工廠方法模式的擴充套件和延伸,但是抽象工廠模式,更有一般性和代表性;它具有工廠方法具有的優點,也增加了解決實際問題的能力。
如圖所示,抽象工廠模式,就好比是兩個工廠方法模式的疊加。抽象工廠建立的是一系列相關的物件,其中建立的實現其實就是採用的工廠方法模式。在工廠Factory中的每一個方法,就好比是一條生產線,而生產線實際需要生產什麼樣的產品,這是由Factory1和Factory2去決定的,這樣便延遲了具體子類的例項化;同時集中化了生產線的管理,節省了資源的浪費。
適用場合
工廠方法模式適用於產品種類結構單一的場合,為一類產品提供建立的介面;而抽象工廠方法適用於產品種類結構多的場合,主要用於建立一組(有多個種類)相關的產品,為它們提供建立的介面;就是當具有多個抽象角色時,抽象工廠便可以派上用場。