策略模式(Strategy Pattern)
定义
定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
设计的原则和思想
- 解耦策略的定义、创建和使用这三部分。
- 不变部分是算法本身,变化的部分是算法的调用。
- 核心思想是动态确定算法(变化)。
一句话概括设计模式
相同的接口,相同的方法,不同的策略。
结构中包含的角色
- Strategy(抽象策略类)
- ConcreteStrategy(具体策略类)
- Context(环境类)
最小可表达代码
// 抽象策略类
abstract class AbstractStrategy
{
public abstract function algorithm();
}
// 具体策略类
class ConcreteStrategy extends AbstractStrategy
{
public function algorithm()
{
echo "具体算法";
}
}
// 环境类
class Context
{
private $strategy;
public function __construct(AbstractStrategy $strategy)
{
$this->strategy = $strategy;
}
public function algorithm()
{
$this->strategy->algorithm();
}
}
$context = new Context(new ConcreteStrategy());
$context->algorithm();
优点
- 可以自由切换算法。
- 避免了多重条件判断。
- 算法单独提取到策略类中,提供了一种算法的复用机制。
缺点
- 因为需要选择合适的策略,客户端需要知道所有的策略算法。
- 任何的变化都将导致系统要增加一个新的具体策略类。
- 客户端每次只能使用一个策略类。
何时使用
- 需要动态地切换不同算法。
- 一个对象有很多的行为,将这些行为转移到相应的具体策略类可以避免维护多重条件语句。
实际应用场景
- 出行是骑自行车, 坐汽车还是走路。
- 一条鱼可以清蒸、红烧、炭烤等。
- 处理订单是同步还是异步。
- 日志记录到数据库,文件还是缓存。
注意
- 算法很少发生改变就没有必要使用这个模式了,使用会让程序更复杂。
- 如果策略多余4个,那么需要使用多个设计模式混合了来解决策略类膨胀的问题了。
策略的定义、创建和使用
策略的定义
一个策略接口和一组实现这个接口的策略类。
策略的创建
为了封装创建逻辑,可以把根据 type 创建策略的逻辑抽离出来,放到工厂类中。
策略的使用
运行时动态确定使用哪种策略,这也是策略模式最典型的应用场景。