在設計模式的學習過程中,builder與factory是建立模式中兩個經典的教程,給與了我們很多值得汲取的寶貴設計思想,然而builder與factory模式也是初學者容易混淆的兩個模式,經常看到有人問及兩者的區別與適用的場景,我在近一段設計模式的學習過程中同樣碰到了這個問題,在兩種模式的區別與聯絡間我看到的更多是後者,在這裡願意與大家分享一些我對builder與factory模式的感悟,有說的不對的地方,還請各位多加提點、指教。
寫在前面
本文旨在兩種模式間的對比與**,因此還希望各位看官首先對兩個模式有一定的了解為好,因為常常看到有人提問說,builder模式與抽象工廠(abstract factory)之間的區別,其實在我看來這兩者間並無太多聯絡,因此也就談不上區別,至於原因在此不做細述,有興趣的朋友可以看看我寫的有關抽象工廠的文章。故本文中所提的factory模式皆指的是工廠方法(factory method)。
從builder到factory的演化
先來看看builder模式,builder模式的一般設計及實現
客戶端呼叫**
1public
class client
2
12 }
從類關係圖上來看,builder模式與我們熟知的工廠模式還是具有一定的區別,最顯著的莫過於這個指導者(director)的角色,我們觀察這個director,發現他無非是以引數的形勢接收了乙個builder,並按照一定的順序呼叫其相應的方法構造各個部件,使得builder可以完成最終的產品。這其實是對複雜物件構造順序的封裝,但我們可以看到僅僅為了做這一件事情是否有必要為它單獨設計乙個類?每次都要例項化這個類的物件呢?既然建造順序是相對穩定的,而且對於客戶來講並不關心這個順序,那麼是否可以將它與builder類結合?當然可以,實際中也確實常常進行這樣的簡化,比如stringbuilder類,我們看不到類似director物件的存在及呼叫。好,那麼經過我們一次的改造以後,變成了如下形式。
客戶端呼叫**
1public
class client
2
11 }
再看看客戶端中的這條builder.construct()語句,似乎也有些多餘了,客戶一般只有在需要產品的時候才會例項化乙個builder物件,因此對於客戶來講,他建立了builder意味著他需要builder能夠為他生成乙個產品(getproduct),而返回產品必然需要構造construct,於是我們又可以對**進一步簡化,將construct方法與getproduct方法結合。
1public
class buildera : ibuilder
2
1011private
void buildpart2()
12
1516public product getresult()
17
24 }
對了,客戶是不關心這個複雜物件的建造生成過程的,也就是說buildpartn(),這些方法對於客戶是沒有意義的,是不可見的,那麼我們就將其宣告為private,而getproduct只是方法的乙個名稱,叫什麼都可以,你可以叫getresult,returnproduct….把它稱為create亦可。ok,之後再來看看改造後的類圖。
omg! 從圖上來看,除了名稱叫做builder外,其他根本和factory模式沒有什麼區別,從**來看,不過是工廠模式在返回具體的產品前對該產品進行了一些初始化的工作。
1//create method in buider
2public product create()
3
就是這些**,我們將其挪個地方改個名稱又何嘗不可呢?
1//create method in buider
2public product create()
3
6//build job move to the product class
7public
class product
8
16 }
builder模式用於建立複雜的物件。
物件內部構建間的建造順序通常是穩定的。
物件內部的構建通常面臨著複雜的變化。
對於持以上觀點的朋友,我也有如下一些疑問。
什麼樣的物件屬於複雜的物件?關於物件複雜與否是如何劃分的?
站在客戶的角度來講,是否關心物件的複雜程度及建造順序?
既然客戶不關心物件是否複雜以及生成的順序,那麼將這個複雜物件分布構建的意義就在於它有益於設計方了,對於設計人員,複雜物件分布構建的分布體現在**?是依次寫幾行**還是依次呼叫幾個方法?
這種分布給你帶來了哪些好處?可以幫助你應付哪些變化?
既然我們不是為了學習設計模式而學習,而是為了學習ood的精髓,能夠編寫出更加靈活,適用於需求變化的軟體。那麼對於需求變化,我們不妨再來看看兩個模式是如何應對的。builder模式適用場景中的第3條提到了"變化"二字:物件內部的構建通常面臨著複雜的變化。就拿parta為例,現在這個物件發生了劇烈的變化,對於builder來講,修改buildparta()方法顯然是違反ocp的,於是採取第二種方法,從抽象builder派生乙個新的newbuilder類,為這個新的builder新增變化後的buildparta()方法,其餘buildpart方法不變。**如下。
1public
class newbuilder : ibuilder
2
1213public
void buildpart2()
14
1819#endregion
2021
public product getresult()
22
25 }
恩,上面的場景對於builder模式的使用,還算比較恰當。如果我們要換成factory呢?一樣可以通過擴充套件來應對變化。
1public
class newfactory : factory
2
15 }
你可能會認為,我改造後的factory就不叫factory了,已經失去了factory的本意,好吧,那我們暫且拋開它的名稱,換個角度來看看builder與factory,builder具有factory應付不了的情況嗎?沒有!因為物件很複雜,所以使用builder構建物件功能更強大,更具有靈活性嗎?沒有!客戶對於取得產品的過程,以及最終產品的使用有區別嗎?沒有!因此builder僅僅是在**的結構上與factory產生了一些異同,使得使用者可以在取得產品前對產品進行一定的初始化工作。如果這也能夠稱為新模式的話,那麼只能說個人對於設計間區別的理解不同。
還有最後要說的一點,關於建造者模式中第2條:物件內部構建間的建造順序通常是穩定的,這點在我看來也難以構成對於與factory模式區別的理由,因為factory模式從來就沒有考慮物件的建造順序!只有不穩定的東西才能帶來變化的可能性,將穩定的不會變化的東西也作為設計模式的理由是否有些牽強了?
分類:
oo design&pattern
好文要頂
關注我收藏該文
Factory模式與Prototype模式的異同
問題 現有兩類產品 1 ram,2 cpu,現在要生成具體的產品 macram,maccpu和winram,wincpu.如下 a abstract c concrete 定義抽象產品ram的類 aprototyperam 同時他也是抽象工廠 abstract class aprototyperam...
簡單工廠與工廠模式 Factory
簡單工廠並不是乙個 真正的 模式,可以把它當作一種程式設計習慣。它的最大優點在於工廠類中包含必要的邏輯判斷,根據客戶端的選擇條件動態例項化相關的類,對於客戶端來說,去除了與具體產品的依賴 工廠方法模式 定義了乙個建立物件的介面,但由於類決定要例項化的類是哪乙個。工廠方法讓類把例項化推遲到子類。要點 ...
factory工廠模式
1.factory模式 兩個重要的功能 1 定義建立物件的介面,封裝了物件的建立 2 使得具體化類的工作延遲到了子類中。factory模式僅僅侷限於一類類 就是說product是一類,有乙個共同的基類 如果我們要為不同類的類提供 乙個物件建立的介面,那就要用abstractfactory了。我們經常...