先前文章有提到,
Simple Factory 主要目的是用來封裝物件創建的過程,
讓主程式與各種方法類別解耦合,視野可以只有Operation與OperationFactory類別即可。
那為什麼又出現 Factory Method 呢?
原因就在於 Simple Factory 在修改部分違背了 開放-封閉 原則。
程式碼請參考 GitHub連結 ( Simple Factory在 Chapter_1.2 , Factory Method 在 Chapter_8.1 )
Factory Method 與 Simple Factory 的類別架構如上圖,
實做計算機當作範例,有加、減和乘的功能,
試著想想看,想要再增加新的功能,例如除法,
在使用 Simple Factory 的情況下,那該怎麼做?
三個步驟:
步驟一:先建立OperationDiv Class
步驟二:接著在 OperationFactory 內增加 "case" 敘述來增加判斷
步驟三:最後在main中修改輸入參數
但這樣不就每次的增減都需要去修改 OperationFactory 的內容嗎?
如大話設計模式內所說的,
"不但對擴展開放了,對修改也開放了"
這就違背了 開放-封閉 原則。
Factory Method 則對於這部分進行了改善,
如果以Factory Method的模式想增加新的除法功能,那我們可以怎麼做?
三個步驟:
步驟一:一樣先增加 OperationSqrt Class(類別內容和剛剛的相同)
步驟二:再建立 DiveFactory Class,用來產生OperationDiv物件
步驟三:最後在 main內把operFactory物件new出DiveFactory即可
有沒有發現兩者的差異?關鍵在於步驟二。
使用Simple Factory的情況下,新增了除法的功能,必須改動既有的程式碼( OperationFactory)。
使用Factory Method的情況下,新增了除法的功能,
卻都沒有對原本既有的程式碼進行修改( main() 的程式碼屬於使用者端,不是開發者端),
這就是利用擴展來新增功能(也可刪除功能),符合 開放-封閉 原則。
使用者得自行new物件,還保有封裝"建立物件過程"的優點嗎?
這時候你可能會想說,Simple Factory模式下使用者只要輸入"+"就有演算法物件,
Factory Method模式下還得把Factory new出來才有演算法物件,
那麼 Factory Method 不就失去了Simple Factory封裝"建立(new)物件過程"的優點嗎?
其實 Factory Method 依然保留著封裝"建立物件過程"的優點,
因為使用者還是看不到最底層演算法(OperationAdd、OperationSub、...)被new的過程,
只能看到Factory,降低使用者與演算法物件的耦合,依然達到保護演算法的作用。
只是 Simple Factory 內的選擇判斷邏輯就移到使用者端(main)去執行(自行選擇Factory去new)。
話說回來,其實只要演算法包成dll,那麼也完全看不到啦...
但作者一直強調這部分,也是我自己的疑問之一,目前的理解是這樣,
所以做個紀錄,目前的我還是有點模糊作者強調這個封裝過程的用意。
符合 開放-封閉 原則的好處
有必要為了符合原則而增加複雜度嗎?多了更多的程式碼!
來看一開始兩者的UML類別圖
可以發現 Simple Factory 的 User Vision 只有 Operation 與 OperationFactory,
Factory Method 的 User Vision 卻還需要多看到(include)四個演算法的工廠,
{AddFactory , SubFactory , MulFactory , DivFactory}
這樣子複雜度不就又提高了嗎?
沒錯,複雜度提高了,但卻符合 開放-封閉 原則。
舉個例子,
以Simple Factory去開發的時候,
想像一下每一個類別都各自由團隊中的一位工程師所負責開發的,
當你在負責 除法 功能類別的時候,寫完了要更新到專案中,
但你此時卻必須去改動別人所負責的OperationFactory類別,客戶才能使用你的除法功能,
假使:
- 負責OperationFactory類別的人請了長假,不開放給人修改
- OperationFactory是個龐大的類別,你也不知道該改動哪裡才OK
- 客戶急著要功能,你也趕工完成,但你一時改動不了OperationFactory(沒授權、不熟悉、不敢改),導致功能無法上線
[這些例子可能不是最適切的,如果有更好的情境歡迎提供。]
如果有以上情境,那是不是要等到負責人回來才能把 除法 功能給使用者使用?
但如果使用 Factory Method ,完成自己的部分之後將軟體發佈出去,
使用者便可以使用最新的功能,不需要修改到其他工程師負責的部分。
唯一的缺點,大概就是需要撰寫新增的功能類別之外,
還得寫對應的 Factory類別,工作量會多一點。
適用情境
以我的經驗來看,如果進行的專案已經是成熟的專案,且變動不大,
例如客戶下訂的是公司內部已經發表一段時間的穩定機台,
那麼該機台內部使用的硬體、元件也相對的固定,臨時替換不同廠牌的可能性不大,
不大可能擴充新的元件進來,這時我會建議使用 Strategy + Simple Factory 作為架構,
把可能使用到的元件都寫進去,方便進行抽換。
但是如果今天進行的專案是嘗試性質、測試性質,
對於機台既有的規格都很模糊,可能嘗試的元件有很多種,需要擴充的機會比較多,
例如目前有三台相機需要做評估,但不確定是否這三台就能滿足需求,
可能還會測試更多品牌的產品,那麼使用 Factory Method 作為架構來開發,
可以保有擴充的彈性。
以團隊分工來看Factory Method
對於團隊分工來說,只要 IFactory 這層介面定義的完善,
就可以讓寫主架構的人不必顧慮負責相機類別的人怎麼實作,
只要能滿足 IFactory 介面所定義的 function 即可。
Factory心得歸納
目前學習了兩個工廠模式,
而工廠模式主要的功能就是讓使用者和產品類別(以上面的例子就是演算法)解開耦合,
只要是工廠,就是為了達成封裝產品物件建立的過程,它的目的是協助產品物件的建立,
而不是產品物件本身的功能。
大話設計模式-工廠方法章節閱讀心得
在110頁和111頁的範例,我覺得情境有點不相符。
作者說為了改善"改一個程式碼就改變所有物件的型別" 所以改成 Factory Method,
但其實簡單工廠模式那個範例(p110)只需要把輸入參數變成變數,
就可以改一次就把全部物件改變型別了,這是第一點。
第二點是,他(p111)的範例其實和(p110)的範例是不相等的,
(p110)簡單工廠的範例是實作三個物件去做三件事情,
但(p111)的範例是實作一個物件去做三件事情,兩者範例觀念其實並不相同。
不一定正確,只是提出了我的疑問。
拖了好久,終於把想寫的完整地寫完了。
============================================================
110/06/18與我的研究所學長Vincent 討論後又有不同的心得,在這邊也補充上來跟大家分享。
本來想融會貫通後直接修改我原本的內容,但學長的舉例都滿完整的,
因此另外記錄在這邊,[ ]內是我的補充。
已知與未知的開發需求數量決定要使用哪一種模式
你在設計 Simple Factory 的時候你無法預估之後會不會加入其他的操作,
下次會不會有"/" "\" 甚至是"asdfasfsd"?你設計期無法知道,
所以在這層面上的需求的話,Simple Factory無法滿足大量"未知"的擴充,
你在設計得時候那些新東西都還連個影子都沒有,只是"可能"需要大量擴充,
[對於擴充這一點需求,可能性的高低影響了不同模式的選擇。]
而 Factory Method 在我把專案release出去後,其他人仍可以沿續設計以低成本擴充,
Simple Factory就非得把判斷邏輯拆開,是寫死的。
[在這邊我的理解是,其實 封裝物件建立,這件事情,是簡單工廠把選擇判斷包裝起來,而工廠方法雖然也有包裝,但不是它真正的重點,它的重點是擴充的方便性,兩者的目標不同。]- 已知+ 已知的未知(或少量未知) -> Simple Factory,成本也低
- 已知 + 大量未知 -> Factory Method
沒有留言:
張貼留言