Delphi模式編程之策略模式
劉 藝
1.1 模式解說
策略(Strategy)模式的用意是定義一組算法(algorithms),并將每個算法封裝到具有共同接口的獨立的類中,從而使它們可以相互替換。策略模式讓算法變化獨立于使用它的客戶端。
要了解策略模式的使用動機和意義,我們得先從一個有趣的例子說起。在一個物料管理系統(tǒng)中,出庫和入庫模塊是該系統(tǒng)的核心部分(下面我們以出庫為例進行分析)。
對于一個沒有面向?qū)ο缶幊探?jīng)驗的程序員,他們往往會把出庫的所有邏輯都放在客戶端(出庫單界面),并在客戶端利用條件分支語句來判斷該出庫單類型是領(lǐng)料、借料還是報損,以便選擇不同的出庫結(jié)算方法,如圖 1‑1所示。這樣一來,客戶端的代碼就變得復(fù)雜和難以維護。比如:需要新增調(diào)撥單類型的出庫時,就要修改判斷條件,重新編譯和發(fā)布客戶端。當情況愈來愈復(fù)雜,條件分支會愈來愈多,添加的程序代碼也會愈來愈多,這樣讓客戶端愈來愈大并難以維護,互相影響和出錯的可能性增大。
圖 1‑1 基于面向過程思想設(shè)計的出庫模塊
如果用面向?qū)ο蟮乃枷雭矸治?,可以把領(lǐng)料單、借料單、報損單看作是出庫單的派生類,如圖 1‑2所示。這樣出庫單作為單據(jù)基類提供單據(jù)的共同接口,而利用繼承的辦法在子類里實現(xiàn)不同的出庫行為。這實際上利用了面向?qū)ο罄锏囊粋€重要概念:多態(tài)。
但是這樣的設(shè)計還有美中不足的地方,這就是環(huán)境和行為緊密耦合在一起。也就是說,單據(jù)和具體出庫的算法緊密耦合在一起。強耦合使得兩者不能獨立演化,限制了重用性和擴展性。
圖 1‑3是利用策略模式重新設(shè)計的出庫模塊。出庫單據(jù)對象通過一個出庫操作對象(即策略模式中的Context)來引用出庫策略對象。各種具體的出庫策略則由出庫策略類的派生類實現(xiàn)。出庫單據(jù)可以由出庫操作和單據(jù)樣式分別提供出庫結(jié)算方法和單據(jù)顯示界面。這樣,策略模式就把出庫的行為從出庫單據(jù)的環(huán)境中獨立出來,出庫算法的增減、修改都不會影響到環(huán)境和客戶端。
圖 1‑2基于面向?qū)ο笏枷朐O(shè)計的出庫模塊
圖 1‑3基于設(shè)計模式思想設(shè)計的出庫模塊
策略模式的優(yōu)勢在于算法和環(huán)境的分離,兩者可以獨立演化。為了更好地說明算法和環(huán)境分離的好處,我們不妨看一下圖 1‑4的設(shè)計。在這個設(shè)計中,已經(jīng)沒有出庫和入庫模塊的概念,因為我將所有出/入庫單據(jù)抽象出來,在運行期動態(tài)組合單據(jù)的界面和行為。通過出/入庫操作類,可以維護、查詢、配置不同的行為類。抽象出的出/入庫行為以策略類的方式封裝了其對應(yīng)的算法,以便完成不同類型的出入庫單據(jù)的操作。這就顯而易見地提高了系統(tǒng)的重用性和可擴展性,減低維護的難度。
圖 1‑4 策略模式的優(yōu)勢在于算法和環(huán)境的分離,兩者可以獨立演化
由此可見,策略模式適用于以下情形:
· 當許多相關(guān)的類之間的差異只在于其行為時。策略模式可以動態(tài)地讓一個對象在許多行為中選擇一種行為。
· 當實現(xiàn)一個目的有多種可選算法時,比如:你出于不同的利弊權(quán)衡考慮定義的那些算法(即相當于應(yīng)用不同的策略)。這些具體的算法可以封裝成抽象算法類的派生類,并享用該抽象算法類的統(tǒng)一接口。通過多態(tài)性,客戶端只要持有一個抽象算法類的對象,就可以選用任何一個具體的算法。
· 當一個算法使用的數(shù)據(jù)不可以讓客戶端得知時。使用策略模式可以避免暴露復(fù)雜的與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)。其實客戶端也沒有必要知道這些與算法相關(guān)的知識和數(shù)據(jù)。
· 當一個類定義有很多行為,且用多個條件語句來判斷選擇這些行為時。策略模式可以把這些行為轉(zhuǎn)移到對應(yīng)的具體策略類中,從而避免了難以維護的多重條件選擇,體現(xiàn)了面向?qū)ο蟮木幊趟枷搿?/DIV>
1.2 結(jié)構(gòu)與用法
策略模式的結(jié)構(gòu)如圖 1‑5所示,它包括了以下參與者:
· 抽象策略(TStrategy)——為所有支持的算法聲明一個共同的接口。TContext使用這個接口調(diào)用由TConcreteStrategy定義和封裝的算法。
· 具體策略(TConcreteStrategy)——封裝了具體算法或行為。實現(xiàn)TStrategy接口。
· 上下文(TContext)——持有一個到TStrategy的引用。調(diào)用TStrategy接口,動態(tài)配置具體算法或行為。
在策略模式中,通過TStrategy和TContext的交互實現(xiàn)所選擇的算法。當算法被調(diào)用時, TContext可以將該算法所需要的所有數(shù)據(jù)都傳遞給該TStrategy?;蛘?,TContext可以將自身作為一個參數(shù)傳遞給TStrategy操作。
當TContext將客戶端請求轉(zhuǎn)發(fā)給它的TStrategy時,客戶通常創(chuàng)建并傳遞一個TConcreteStrategy對象給該TContext;這樣, 客戶端僅與TContext交互。通常有一系列的TConcreteStrategy類可供客戶端從中選擇。
-------------------------------------------------------------------------------------------
更多相關(guān)文章和示例程序源代碼可以到作者網(wǎng)站下載:
http://www.liu-yi.net