Strategy模式:
定義一系列的演算法,把他們一個個封裝起來,並且是他們可以相互替換,Strategy模式使演算法可以獨立於使用它的使用者而變化。
具體來說,策略模式的關鍵特徵包括:
意圖:可以根據上下文,使用不同的商務規則或者演算法。問題:對所需演算法的選擇取決於發出請求的使用者或則要處理的資料。如果只有一些不會變化的演算法,就不需要該模式。解決方案:對演算法的選擇和演算法的實現相分離。允許根據上下文進行選擇。參與者與共同作業者:。。。。。。。。。效果:定義了一系列的演算法。可以不適用條件陳述式或者switch語句來調用。各個演算法擁有相同的介面。實現:讓使用演算法的類包含一個抽象類別,該抽象類別具有一個抽象方法指定如何調用演算法。每個衍生類別按照需要實現演算法。
根據物件導向的一些忠告:“考慮設計中什麼是可變的”,“對變化的概念進行封裝”,“優先使用對象組合聚集,而不是類繼承”。由此我們的作法是:
1.尋找變化,將他封裝在一個單獨的類中。2.將這個類包含在另一個類中。
《深入php物件導向模式和實踐》中給出的策略模式的例子:
假設我們已經穿撿了一個標記語言,現在測試需要一些問題,因此我們建立了Question類,並為其添加了mark( )方法。假設使用者回答問題時可以使用多種不同的標記方式,應該怎麼辦呢?
比如,現在要支援簡單的markLogic語言,直接匹配以及Regex匹配三種標記方式。可能首先想到的是使用子類來實現。
如果只是這一個方面的需求,這麼做還是能夠適應我們的需求的,但是如果我們被要求支援不同的類型==基於文本的問題和基於多媒體的問題,在一個繼承樹中穿件多個子類的方案會產生一些問題。
因此,“只要發現自己正在不斷地在幾成熟的各個分支中重複同一個演算法(無論是通過子類還是通過重複條件陳述式)請將這些演算法封裝成獨立的類型。”。
UML圖示:
實現:
abstract class Question{ protected $promp; protected $marker; public function __construct($promp,Marker $marker){ $this->marker = $marker; $this->promp = $promp; } abstract function mark($response);}
class TextQuestion extends Question{ public function mark($response){ echo "[text-response:]".$response.PHP_EOL; return $this->marker->mark($response); }}
class AVQuestion extends Question{ public function mark($response){ echo "[Av-response:]".$response.PHP_EOL; return $this->marker->mark($response); }}
class MarkLogicMarker extends Marker{ private $engine; public function __construct( $test ){ parent::__construct($test); $this->engine = new MarkPaser($test); } public function mark($response){ return $this->engine->evaluate( $response ); }}
class MatchMarker extends Marker{ public function mark($response){ return ($this->test == $response); }}
class RegexMarker extends Marker{ public function mark($response){ return ( preg_match($this->test,$response) ); }}
class Config{ public static $configs = array( 'what is baby?'=>'yes', 'how can i love U?'=>'of course', 'may be tomorrow?'=>'yeah', 'should it be like this?'=>'maybe', 'the result is?'=>'1+1', );}
class MarkParser{ private $test; public function __construct($test){ $this->test = $test; } public function evaluate( $response ){ assert($response); assert(in_array($response,array_keys(Config::$configs))); return Config::$configs[$response]; }}