簡介
策略模式定義了演算法族,分別封裝起來,讓他們之間可以相互替換。該模式讓演算法獨立於使用它的客戶而獨立變化。
組成
抽象策略角色: 策略類,通常由一個介面或者抽象類別實現。
具體策略角色:封裝了相關的演算法和行為。
環境角色:持有一個策略類的引用,最終給用戶端調用。
應用情境
多個類只區別在表現行為不同,可以使用原則模式,在運行時動態選擇具體要執行的行為。
需要在不同情況下使用不同的策略(演算法),或者策略還可能在未來用其它方式來實現。
對客戶隱藏具體策略(演算法)的實現細節,彼此完全獨立。
實現
步驟
定義抽象角色類(定義好各個實現的共同抽象方法)
定義具體策略類(具體實現父類的共同方法)
定義環境角色類(接收儲存執行個體,統一執行策略類介面方法)
代碼
<?phpheader('Content-Type:text/html;charset=utf-8');/** * 策略模式示範代碼 * * 為了更好地突出“策略”,我們這裡以出行為例示範,日常出行大概分為以下幾種工具:自駕車,公交車,地鐵,火車,飛機,輪船 * * 下面一起看代碼,領會何為策略模式 *//** * Interface Travel 抽象策略角色 * 約定具體方法 */interface Travel{ public function go();}/** * Class selfDriving 具體策略角色 * 自駕車 */class bySelfDriving implements Travel{ public function go() { echo '我自己開著車出去玩<br>'; }}/** * Class byBus具體策略角色 * 乘公交 */class byBus implements Travel { public function go() { echo '我乘公交出去玩<br>'; }}/** * Class byMetro 具體策略角色 * 乘地鐵 */class byMetro implements Travel{ public function go() { echo '我乘地鐵出去玩<br>'; }}/** * Class byTrain 具體策略角色 * 乘火車 */class byTrain implements Travel{ public function go() { echo '我乘火車出去玩<br>'; }}/** * Class byAirplane 具體策略角色 * 乘飛機 */class byAirplane implements Travel{ public function go() { echo '我乘飛機出去玩<br>'; }}/** * Class bySteamship 具體策略角色 * 乘輪船 */class bySteamship implements Travel{ public function go() { echo '我乘輪船出去玩<br>'; }}/** * Class Mine 環境角色 */class Mine{ private $_strategy; private $_isChange = false; /** * 構造方法 * 此處使用到了依賴注入和類型約束的概念,詳情請參考 * 1.聊一聊PHP的依賴注入(DI) 和 控制反轉(IoC) * @link https://segmentfault.com/a/1190000007209266 * 2.淺談PHP的類型約束 * @link https://segmentfault.com/a/1190000007226476 * * @param Travel $travel */ public function __construct(Travel $travel) { $this->_strategy = $travel; } /** * 改變出行方式 * * @param Travel $travel */ public function change(Travel $travel) { $this->_strategy = $travel; $this->_isChange = true; } public function goTravel() { if ($this->_isChange) { echo '現在改變主意,'; $this->_strategy->go(); } else { $this->_strategy->go(); } }}/** * 用戶端使用 */$strategy = new Mine(new byBus());// 乘公交$strategy->goTravel();// 乘地鐵$strategy->change(new byMetro());$strategy->goTravel();// 自駕車$strategy->change(new bySelfDriving());$strategy->goTravel();// 其他根據具體應用選擇實現
運行結果
我乘公交出去玩
現在改變主意,我乘地鐵出去玩
現在改變主意,我自己開著車出去玩
優缺點
優點
策略模式提供了管理相關的演算法族的辦法。策略類的等級結構定義了一個演算法或行為族。恰當使用繼承可以把公用的代碼轉移到父類裡面,從而避免重複的代碼。
策略模式提供了可以替換繼承關係的辦法。繼承可以處理多種演算法或行為。如果不是用策略模式,那麼使用演算法或行為的環境類就可能會有一些子類,每一個子類提供一個不同的演算法或行為。但是,這樣一來演算法或行為的使用者就和演算法或行為本身混在一起。決定使用哪一種演算法或採取哪一種行為的邏輯就和演算法或行為的邏輯混合在一起,從而不可能再獨立演化。繼承使得動態改變演算法或行為變得不可能。
使用原則模式可以避免使用多重條件轉移語句。多重轉移語句不易維護,它把採取哪一種演算法或採取哪一種行為的邏輯與演算法或行為的邏輯混合在一起,統統列在一個多重轉移語句裡面,比使用繼承的辦法還要原始和落後。
缺點
用戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味著用戶端必須理解這些演算法的區別,以便適時選擇恰當的演算法類。換言之,策略模式只適用於用戶端知道所有的演算法或行為的情況。
策略模式造成很多的策略類,每個具體策略類都會產生一個新類。有時候可以通過把依賴於環境的狀態儲存到用戶端裡面,而將策略類設計成可共用的,這樣策略類執行個體可以被不同用戶端使用。換言之,可以使用享元模式來減少對象的數量。