設計模式之 策略模式
策略模式屬於對象行為型的設計模式
定義 :封裝了一些列算法,它們之前可以相互替換,此模式使得算法的改變,不會影響到使用它們的客戶端
策略模式有以下3個角色組成
抽象策略類 : 所有策略類的父類,為所支持的策略算法聲明了抽象方法
具體策略類 :實現抽象策略類的方法
Context環境類 : 維護一個對Strategy對象的引用
策略模式分離了算法的定義和使用,要做到這樣客戶端要依賴於策略接口,而不是具體的實現所有策略類對象可以互相替換,說明具有共同的特性->行為相同
以下是PHP對上述UML的實現
<?php /* *抽象策略類 */ abstract class Stratrgy{abstract function AlgorithmInterface(); } //具體實現類A class ConcreateStratrgyA extends Stratrgy{ public function AlgorithmInterface() { echo ‘算法A‘, PHP_EOL; } } //具體實現類B class ConcreateStratrgyB extends Stratrgy{ public function AlgorithmInterface() { echo ‘算法B‘, PHP_EOL; } }//具體實現類C class ConcreateStratrgyC extends Stratrgy{ public function AlgorithmInterface() { echo ‘算法C‘, PHP_EOL; } } //上下文環境類 class Context{ private $_strategy; //通過構造方法註入策略對像 public function __construct(Stratrgy $strategy) { $this->_strategy = $strategy; } publicfunction ContextInterface(){ $this->_strategy->AlgorithmInterface(); } } //客戶端類 class Client{ public static function main(){ $context = new Context(new ConcreateStratrgyA()); $context->ContextInterface(); $context = new Context(new ConcreateStratrgyB()); $context->ContextInterface(); $context = new Context(new ConcreateStratrgyC()); $context->ContextInterface(); } } Client::main();
在實際開發中,我們項目裏很多地方都用到了策略模式,這裏以支付回調為栗子介紹下策略模式在我們項目中的應用。
首先所有的支付回調都是由第三方發起,行為相同,最終都是給用戶發送道具並通知第三方。整個流程可以抽象為3個步驟 :驗證第三方參數 ->發送道具給用戶 ->返回報文給第三方,因此我們的抽象策類裏可以定義3個抽象方法,另外一些公共使用的方法都可以放到抽象
策略類裏,具體策略類只需要繼承就可以復用。策略環境類這裏做了一些改動,加入了簡單工廠模式生成具體的策略對象。每種支付的參數驗證,發具體的道具數,以及報文響應都不相同,具體的支付類需要實現3個抽象方法。
由微信切換成支付寶,需要增加對應的支付寶類,然後回調的時候在工廠方法傳入支付寶參數即可,這樣微信,支支付寶...達到了相互替換的目的,而且具體的支付寶微信類改變不會影響到回調的入口。
抽簡後的代碼如下:
<?php //抽象策略類 abstract class StrategyNotify{ //參數檢查 abstract function checkParam(); //發送道具 abstract function sendProp(); //輸出報文 abstract function outputMessage(); //支付回調狀態 protected $_status = -1; //第三方參數 protected $_params = array(); protected $_errMsg = array( ‘-1‘=>‘系統錯誤‘, ‘-2‘=>‘參數驗證錯誤‘, ‘-3‘=>‘發送道具失敗‘, ); //通知方法 public final function notify(){ if(!$this->checkParam()){ $this->_status = -2; }else if(!$this->sendProp()){ $this->_status = -3; }else{ $this->_status = 1; } if($this->_status != 1){ $this->log(); } $this->outputMessage(); } //寫日誌例子 protected function log(){ echo isset($this->_errMsg[$this->_status]) ? $this->_errMsg[$this->_status] : ‘‘; echo PHP_EOL; } } //微信支付 class Weixin extends StrategyNotify{ public function checkParam() { return false; } public function outputMessage() { if($this->_status === 1){ die(‘OK‘); }else{ die(‘FAIL‘); } } public function sendProp() { return false; } } //支付環境類 class Pay{ private static $_notify = null; //策略工廠 public static function factory($notify){ if(class_exists($notify) && self::$_notify == null){ self::$_notify = new $notify(); } return self::$_notify; } } Pay::factory(‘Weixin‘)->notify();
總結
優點:
1.當新增策略的時候,只需要增加具體的策略類,達到了開閉原則的目的
2.分離了算法的定義和使用,使得算法可以復用
缺點
1.每增加一個策略就需要增加一個策略類(目前我們的app接近200種支付,意味著有200個子類)
2.無法在客戶端同時使用兩種策略(我們的支付下單,需要從多種支付依照優先級一個個去下單,直到成功為止)
設計模式之 策略模式