軟體開發的天空


SINCE 2004

最新回應

之前筆者發表過兩篇關於Design Patterns議題的文章,用意是讓讀者能夠初步瞭解Strategy Pattern與Simple Factory Pattern的概念以及應用的方式,不過在現實世界中的應用情況往往還要更複雜些。因此,本篇文章中我們將進一步探討在MicroSoft.Net的平台上實際應用Strategy Pattern概念時會遭遇什麼樣的問題,以及應該如何解決。

在本篇文章最後,我們將會完成一個實務應用,讓演算法獨立為一顆元件(DLL),而要使用演算法的軟體系統只需要使用參數來設定組件名稱,就可以直接將演算法元件掛上系統,不需要重新編寫程式或者編譯,就彷彿是電腦的USB介面一般,隨插即用。

系統分析與設計

如同之前文章所解釋的,Strategy Patten的用途是當我們在設計系統,面對需要彈性抽換商業邏輯或者演算法議題時,用來將客戶端以及演算法的物件之間鬆綁的解決方式,用比較容易理解的說法,我們可以說Strategy就如同是一個Switch在運作著,使得系統可以在不同的演算法之間作彈性切換。

請看以下的表格,裡面有三個演算法需要做處理。

輸入值

演算法名稱

運算規則

A

StrategyOne

A * 5 + 10

A

StrategyTwo

A * 10

A

StrategyThree

A * 2

依照之前我們提過的原則,我們會將所有的演算法設計一個共同的介面,並且打算讓三個演算法都實做這個介面,讓客戶端的程式只能接觸到這個介面,來達到與客戶端之間的程式鬆綁的目的,如下圖。

像這樣的架構在客戶端可以在程式中依造情況切換至不同的演算法物件,但是明眼人其實看的出來這樣是有缺陷的。在我們可以想像的情境底下,客戶端的程式功能大概是抵定不太會再做變動的,會有變動機會的其實就是實際執行更換演算法的程式部份。此外,還有一個問題就是,客戶端在實做IStrategy物件時,還是難免會接觸到演算法物件,這樣其實就失去了我們使用介面的美意了,實體演算法物件的類別名稱還是寫死在程式裡了。

依照物件導向的隔離原則,我們會希望將容易變動與不會變動的部份隔離開來,以免因為修改或擴充時影響既有的程式而造成預期之外的狀況發生。因此我們可以再調整成下面的架構。

依照上圖的架構,我們會將切換演算法的工作放到StrategySimpleFactory物件裡,這麼一來客戶端就不會接觸到最後實際的演算法類別,也就是說我們將會變動的部分都抽離集中到StrategySimpleFactory了,如同下面的程式,客戶端只剩下兩行程式就解決了,而且永遠不需要知道究竟實做了哪個演算法類別。

IStrategy obj;
obj = (IStrategy)StrategySimpleFactory.GetStrategy();

還記得文章ㄧ開始提到的嗎?我們要完成的是可以掛載演算法元件的系統,怎麼現在都還將選擇演算法類別的程式寫在SimpleFactory裡面,所以我們還有一段路要走,請再集中一下精神吧。

系統實做

接下來我們要重新調整一下我們的架構,由於我們最後要掛載演算法元件,因此我們將把演算法實作的類別獨立在一個類別庫專案裡。然後將客戶端建立一個WindowForm專案。最後IStragety介面由於同時需要被實作的演算法以及客戶端參考到,所以將這個介面獨立出來成為一個類別庫專案讓其他兩個專案參考。

首先我們要先完成IStrategy介面的類別庫,如同下列程式碼。

接著,我們在演算法類別庫中實作兩個IStrategy的演算法類別,分別是StrategyOne以及StrategyTwo。

等等,不是說有三個演算法嗎,第三個呢?
請先稍安勿躁,往下看就會知道了。

在本文前面曾經提過,SimpleFactory被視作是一個Switch在運作,此時程式中實際上並沒有出現實際進行切換演算法的程式碼,而是被動態繫結的程式碼所取代。

這段程式的作用是這樣的,它會依照傳入的參數組成組件與類別名稱,然後以動態繫結的方式載入該顆元件並且建立該型別的執行個體。最後再將建立的執行個體給傳回客戶端程式。也就是說,原來用來切換的動作我們用一個外部參數傳入系統的方式來取代,直接依照傳入的演算法名稱來連結到不同的演算法類別,並進行實做。

從上面的程式我們會發現實際建立物件的函式有兩個,分別是test()以及test2。這兩者的差異性在於test1是用來建立其他組件中的類別的執行個體的,也就是本篇文章主題中所提到的,可以抽換的獨立元件(DLL檔案)。

那麼test2的作用是什麼呢?

該函式的作用是如果系統要掛載的演算法類別是存在於同一顆組建中時,可以以該函式內的方式建立。使用的時機是例如我們用彈性動態繫結的方式建立演算法類別,但是又不希望元件獨立出來,可能有安全性的考量時,便可以折衷使用這樣的方式,讓演算法可以獨立維護也亦於擴充。因此筆者將第三個演算法放置在這個專案中,將會隨著本專案編譯在同一顆組建內。

第三個演算法如下。

最後讓我們看一下客戶端的程式,很單純的幾行程式而已。

實際部署

如同下圖所示,被掛載的StrategyImplement.dll需放置在系統執行檔的同一路徑下(若是Web系統,則放置於bin目錄下),不需要被參考至該專案內,當系統執行時會以動態繫結的方式載入該顆元件,並建立執行個體。

由於爲了讓抽換與掛載的效果突顯出來,因此筆者選擇用參數傳入的方式來動態掛載型別,但是實際上在系統設計時我們可以選擇用設定檔的方式來設定要抽換的元件。也可以選擇設計一個後台的管理介面,將組件檔的資訊記錄在資料庫裡,使用設定的方式完成皆可,端看系統架構規劃的方向決定。

執行的畫面如下所示:

演算法一


按下Test執行得到運算結果


演算法二


按下Test執行得到運算結果


演算法三,該演算法是放置於這個Windows Form組件內


按下Test2執行得到運算結果

在本篇文章中我們嘗試了如何利用Strategy以及Simple Factory兩個Pattern來設計一個彈性高的系統,不過其實這樣的設計理念是處處可見的。下一篇文章中,我們將探討在MicroSoft.Net的Framework也應用了這樣的理念而設計出來的架構,它也讓我們能夠設計自己的元件掛載到Framework的運作流程中,很意外嗎?請拭目以待。


回應

目前沒有回應.

*標  題:

*姓  名:

  電子郵件: (將不會被顯示)

  個人網頁:

*回應

登入後使用進階評論

Please add 2 and 5 and type the answer here: