策略模式简介
意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
关键代码:实现同一个接口。
优点:
-
算法可以自由切换。
-
避免使用多重条件判断。
-
扩展性良好。
缺点:
- 策略类会增多。
- 所有策略类都需要对外暴露。
使用场景:
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
**注意事项:**如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
与现有业务结合
- 楼盘列表筛选、排序、
实现demo
- 实现抽象类,抽象算法的共性
<?php
namespace ApiClient\services\project_search;
/**
* 楼盘列表排序接口
*/
abstract Class AlgorithmInterface
{
/**
* 用户筛选条件
* @var array
*/
protected $filter;
/**
* 用户搜索内容
* @var string
*/
protected $keyword;
/**
* 设置筛选条件
* @param [type] $filter [description]
*/
public function setFilter($filter)
{
$this->filter = $filter;
}
/**
* 获取筛选条件
* @param [type] $filter [description]
*/
public function getFilter()
{
return $this->filter;
}
/**
* 设置搜索内容
* @param [type] $filter [description]
*/
public function setKeyword($keyword)
{
$this->keyword = $keyword;
}
/**
* 获取搜索内容
* @param [type] $filter [description]
*/
public function getKeyword()
{
return $this->keyword;
}
/**
* 具体算法实现方法
* @return mixed
*/
public abstract function algorithmImplementation();
}
- 继承抽象类,实现不同算法策略
<?php
namespace ApiClient\services\project_search;
use ApiClient\services\project_search\AlgorithmInterface;
class OpenSearchService extends AlgorithmInterface
{
/**
* opensearch 排序策略实现
* @return mixed
*/
public function algorithmImplementation()
{
echo "open search 策略实现";
// echo $this->aa();
return;
}
}
<?php
namespace ApiClient\services\project_search;
use ApiClient\services\project_search\AlgorithmInterface;
class ScreeningAlgorithmService implements AlgorithmInterface
{
/**
* opensearch 排序策略实现
* @return mixed
*/
public function algorithmImplementation() {
echo "算法筛选 策略实现";
}
}
<?php
namespace ApiClient\services\project_search;
use ApiClient\services\project_search\AlgorithmInterface;
class SortAlgorithmService implements AlgorithmInterface
{
/**
* opensearch 排序策略实现
* @return mixed
*/
public function algorithmImplementation() {
echo "算法排序 策略实现";
}
}
- 业务代码调用
if (...) {
$project_ids = new OpenSearchService()->algorithmImplementation;
} elseif (...) {
$project_ids = new ScreeningAlgorithmService()->algorithmImplementation;
}
- 优化 - 封装算法判断逻辑
<?php
namespace ApiClient\services\project_search;
/**
* 策略工厂结合
*/
class SearchContextService
{
/**
* 算法对象
* @var object
*/
private $algorithm_object;
/**
* __construct
* @param string $algorithm_type 选择的算法类型
*/
public function __construct($algorithm_type)
{
if ($algorithm_type == 1) {
$this->algorithm_object = new OpenSearchService();
} elseif ($algorithm_type == 2) {
$this->algorithm_object = new ScreeningAlgorithmService();
}
}
/**
* 获取算法策略结果,无需关注具体策略实现
* @return array
*/
public function getResult()
{
return $this->algorithm_object->algorithmImplementation();
}
}
- 再优化 - 策略、简单工厂结合
<?php
namespace ApiClient\services\project_search;
/**
* 策略工厂结合
*/
class SearchContextService
{
/**
* 算法对象
* @var object
*/
private $algorithm_object;
public $aa = 1;
/**
* 算法类型映射
* @var array
*/
private $algorithm_type_map = [
'A' => 'ApiClient\services\project_search\OpenSearchService',
'B' => 'ApiClient\services\project_search\ScreeningAlgorithmService',
'C' => 'ApiClient\services\project_search\SortAlgorithmService'
];
/**
* __construct
* @param string $algorithm_type 选择的算法类型
*/
public function __construct($algorithm_type, $filter)
{
// 创建算法类实例
$this->algorithm_object = new $this->algorithm_type_map[$algorithm_type];
$this->algorithm_object->setFilter($filter);
}
/**
* 获取算法策略结果,无需关注具体策略实现
* @return array
*/
public function getResult()
{
// var_dump($this->algorithm_object->getFilter());
return $this->algorithm_object->algorithmImplementation();
}
}
总结
- 装饰模式可让你更改对象的外表, 策略模式则让你能够改变其本质。