一. 策略模式理论
策略模式是一种定义一系列算法的方法,从概念上看,所有这些算法都是完成的相同的工作,只是实现不同,他可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
二. 如何理解?
其实举个例子来说,上一篇文章里我们使用了简单工厂设计模式来实现了一个加减法的操作。对于加法和减法来说,在概念上看都是对两个数字进行运算,再统一的将结果返回。本质上都是完成的运算这样相同的工作,只是怎么运算,怎样运算,这之间有所不同。
所以说如果你面临着类似于这种需求场景,就可以考虑用策略模式来实现它了。
其实我们发现了,不仅仅是算法,只要是规则,变化等都可以使用策略模式。
"策略模式封装了变化"
将变化封装进“策略模式”内部,减少了“客户”使用我们写的代码的使用复杂度。
三. 策略模式的优点
1.减少算法类和使用算法类之间的耦合
2.简化单元测试,每个算法都有自己的类。可以通过自己的接口单独测试。
3.任意修改其中的任何一个算法也不会影响到其他算法。
四. 策略模式的实现结构
五. 策略模式的具体实践
下面是加减法的策略模式的实现:
<?php
# 运算基类
abstract class Operation{
# 获得结果
abstract function algorithm(int $a, int $b):int;
}
# 加法
class Add extends Operation{
# 实现加的算法
public function algorithm(int $a, int $b):int
{
return $a + $b;
}
}
# 加法
class Sub extends Operation{
# 实现减的算法
public function algorithm(int $a, int $b):int
{
return $a - $b;
}
}
# 算法使用类
class Context{
private $operationObj = NULL;
function __construct(Operation $opObj){
$this->operationObj = $opObj;
}
function getResult(int $a, int $b){
return $this->operationObj->algorithm($a, $b);
}
}
# 客户端
$operation = "+";
if($operation === "+"){
$c = new Context(new Add());
echo $c->getResult(1,2);
}
echo "<br />";
$operation = "-";
if($operation === "-"){
$c = new Context(new Sub());
echo $c->getResult(1,2);
}
code Out:
3
-1
我们上一篇文章是使用的简单工厂模式来实现的加减法,而这篇是使用的策略模式实现的。说了这么多,到底是用简单工厂模式呢还是策略模式呢?其实没有什么特别的说法和限制,一个项目设计模式遍布各个角落。肯定不能以单一的设计模式来贯穿整个项目。
六. 策略模式与工厂模式结合实现
上篇文章讲到工厂设计模式就是把实例化对象的步骤放在了factory类中,是用工厂方法代替new操作的一种模式。那么掌握了这一点策略模式与工厂模式结合的方式也有了具体的思路了,那就是将客户端内实例化对象的代码(下面的代码)迁移到策略模式内部。
# 原客户端代码
$operation = "+";
if($operation === "+"){
$c = new Context(new Add());
echo $c->getResult(1,2);
}
$operation = "-";
if($operation === "-"){
$c = new Context(new Sub());
echo $c->getResult(1,2);
}
修改后实现了策略模式与简单工厂模式的结合:
<?php
# 运算基类
abstract class Operation{
# 获得结果
abstract function algorithm(int $a, int $b):int;
}
# 加法
class Add extends Operation{
# 实现加的算法
public function algorithm(int $a, int $b):int
{
return $a + $b;
}
}
# 加法
class Sub extends Operation{
# 实现减的算法
public function algorithm(int $a, int $b):int
{
return $a - $b;
}
}
# 算法使用类
class Context{
private $operationObj = NULL;
function __construct(string $operation){
if($operation === "+"){
$this->operationObj = new Add();
}
if($operation === "-"){
$this->operationObj = new Sub();
}
}
function getResult(int $a, int $b){
return $this->operationObj->algorithm($a, $b);
}
}
# 客户端
$c = new Context("+");
echo $c->getResult(1,2);
echo "<br />";
$c = new Context("-");
echo $c->getResult(1,2);
把用于判断是加法还是减法和实例化不同加法类减法类的对象的代码由客户端迁移到了Context类内部。
这样做明显相对于刚才的代码使用起来更加精简了,最多只需要两行就可以调用得出结果。并且客户端不用引入Sub,Add......等各类算法类了。只需要跟Context做交互传递参数即可。
if($operation === "-"){
$c = new Context(new Sub());
echo $c->getResult(1,2);
}
$c = new Context("+");
echo $c->getResult(1,2);
episode
现在的代码基本上来看设计的很精简了,只是if...if让人感觉很粗糙。而且在项目中如果使用大量的if...else...会造成难代码难以维护,可读性差等很多痛点。那么如何做到替代分支语句呢?其实现在的策略模式还不够完美,我们可以用反射技术来做,以后我们会讲到反射。