Strategy模式:
定义一系列的算法,把他们一个个封装起来,并且是他们可以相互替换,Strategy模式使算法可以独立于使用它的用户而变化。
具体来说,策略模式的关键特征包括:
意图:可以根据上下文,使用不同的业务规则或者算法。
问题:对所需算法的选择取决于发出请求的用户或则要处理的数据。如果只有一些不会变化的算法,就不需要该模式。
解决方案:对算法的选择和算法的实现相分离。允许根据上下文进行选择。
参与者与协作者:。。。。。。。。。
效果:定义了一系列的算法。可以不适用条件语句或者switch语句来调用。各个算法拥有相同的接口。
实现:让使用算法的类包含一个抽象类,该抽象类具有一个抽象方法指定如何调用算法。每个派生类按照需要实现算法。
根据面向对象的一些忠告:“考虑设计中什么是可变的”,“对变化的概念进行封装”,“优先使用对象组合聚集,而不是类继承”。由此我们的作法是:
1.寻找变化,将他封装在一个单独的类中。
2.将这个类包含在另一个类中。
《深入php面向对象模式和实践》中给出的策略模式的例子:
假设我们已经穿捡了一个标记语言,现在测试需要一些问题,因此我们创建了Question类,并为其添加了mark( )方法。假设用户回答问题时可以使用多种不同的标记方式,应该怎么办呢?
比如,现在要支持简单的markLogic语言,直接匹配以及正则表达式匹配三种标记方式。可能首先想到的是使用子类来实现。
如果只是这一个方面的需求,这么做还是能够适应我们的需求的,但是如果我们被要求支持不同的类型==基于文本的问题和基于多媒体的问题,在一个继承树中穿件多个子类的方案会产生一些问题。
因此,“只要发现自己正在不断地在几成熟的各个分支中重复同一个算法(无论是通过子类还是通过重复条件语句)请将这些算法封装成独立的类型。”。
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];
}
}