策略模式: 策略模式(Strategy Pattern):定義一系列演算法,將每一個演算法封裝起來,並讓它們可以相互替換。策略模式讓演算法獨立於使用它的客戶而變化,也稱為政策模式(Policy)。 策略模式是一種對象行為型模式。 模式動機: 完成一項任務,往往可以有多種不同的方式,每一種方式稱為一個策略, ...
策略模式:
策略模式(Strategy Pattern):定義一系列演算法,將每一個演算法封裝起來,並讓它們可以相互替換。策略模式讓演算法獨立於使用它的客戶而變化,也稱為政策模式(Policy)。
策略模式是一種對象行為型模式。
模式動機:
完成一項任務,往往可以有多種不同的方式,每一種方式稱為一個策略,我們可以根據環境或者條件的不同選擇不同的策略來完成該項任務。
在軟體開發中也常常遇到類似的情況,實現某一個功能有多個途徑,此時可以使用一種設計模式來使得系統可以靈活地選擇解決途徑,也能夠方便地增加新的解決途徑。
在軟體系統中,有許多演算法可以實現某一功能,如查找、排序等,一種常用的方法是硬編碼(Hard Coding)在一個類中,如需要提供多種查找演算法,可以將這些演算法寫到一個類中,在該類中提供多個方法,每一個方法對應一個具體的查找演算法;當然也可以將這些查找演算法封裝在一個統一的方法中,通過if…else…等條件判斷語句來進行選擇。這兩種實現方法我們都可以稱之為硬編碼,如果需要增加一種新的查找演算法,需要修改封裝演算法類的源代碼;更換查找演算法,也需要修改客戶端調用代碼。在這個演算法類中封裝了大量查找演算法,該類代碼將較複雜,維護較為困難。
角色分析:
抽象策略角色:策略類,通常由一個介面或者抽象類實現。
具體策略角色:包裝了相關的演算法和行為。
環境角色:持有一個策略類的引用,最終給客戶端調用。
UML類圖:
代碼實現:
<?php header("Content-type:text/html;Charset=utf-8"); //抽象策略介面 abstract class Strategy{ abstract function wayToSchool(); } //具體策略角色 class BikeStrategy extends Strategy{ function wayToSchool(){ echo "騎自行車去上學"; } } class BusStrategy extends Strategy{ function wayToSchool(){ echo "乘公車去上學"; } } class TaxiStrategy extends Strategy{ function wayToSchool(){ echo "騎計程車去上學"; } } //環境角色 class Context{ private $strategy; //獲取具體策略 function getStrategy($strategyName){ try{ $strategyReflection = new ReflectionClass($strategyName); $this->strategy = $strategyReflection->newInstance(); }catch(ReflectionException $e){ $this->strategy = ""; } } function goToSchool(){ $this->strategy->wayToSchool(); // var_dump($this->strategy); } } //測試 $context = new Context(); $context->getStrategy("BusStrategy"); $context->goToSchool(); ?>
優點:
1、 策略模式提供了管理相關的演算法族的辦法。策略類的等級結構定義了一個演算法或行為族。恰當使用繼承可以把公共的代碼轉移到父類裡面,從而避免重覆的代碼。
2、 策略模式提供了可以替換繼承關係的辦法,繼承可以處理多種演算法或行為。如果不是用策略模式,那麼使用演算法或行為的環境類就可能會有一些子類,每一個子類提供一個不同的演算法或行為。但是,這樣一來演算法或行為的使用者就和演算法或行為本身混在一起。決定使用哪一種演算法或採取哪一種行為的邏輯就和演算法或行為的邏輯混合在一起,從而不可能再獨立演化。繼承使得動態改變演算法或行為變得不可能。
3、 使用策略模式可以避免使用多重條件轉移語句。
多重轉移語句不易維護,它把採取哪一種演算法或採取哪一種行為的邏輯與演算法或行為的邏輯混合在一起,統統列在一個多重轉移語句裡面,比使用繼承的辦法還要原始和落後。
缺點:
1、客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。
這就意味著客戶端必須理解這些演算法的區別,以便適時選擇恰當的演算法類。換言之,策略模式只適用於客戶端知道所有的演算法或行為的情況。
2、 策略模式造成很多的策略類,每個具體策略類都會產生一個新類。
有時候可以通過把依賴於環境的狀態保存到客戶端裡面,而將策略類設計成可共用的,這樣策略類實例可以被不同客戶端使用。換言之,可以使用享元模式來減少對象的數量。