15 05 2020

策略模式

模式定义

策略模式(Strategy),又叫算法簇模式,定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化,即封装变化的算法。


策略模式的优势

易于扩展,增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合开放封闭原则 

使用策略模式可以避免使用多重条件转移语句(if ... else) 

策略类之间可以自由切换,由于策略类都实现同一个接口,所以使它们之间可以自由切换 每个策略类使用一个策略类,符合单一职责原则 

客户端与策略算法解耦,两者都依赖于抽象策略接口,符合依赖反转原则 

客户端不需要知道都有哪些策略类,符合最小知识原则


策略模式的缺陷

策略模式,当策略算法太多时,会造成很多的策略类

客户端不知道有哪些策略类,不能决定使用哪个策略类,可以考虑使用IOC容器和依赖注入的方式来解决


代码示例

Strategy\ComparatorInterface.class.php
<?php
namespace Strategy;

interface ComparatorInterface
{
    public function compare($a, $b);
}


Strategy\DateComparator.class.php
<?php
namespace Strategy;

class DateComparator implements ComparatorInterface
{
    public function compare($a, $b)
    {
        $aDate = strtotime($a['date']);
        $bDate = strtotime($b['date']);

        if($aDate == $bDate) {
            return 0;
        } else {
            return $aDate < $bDate ? -1 : 1;
        }
    }
}


Strategy\IdComparator.class.php
<?php
namespace Strategy;

class IdComparator implements ComparatorInterface
{
    public function compare($a, $b)
    {
        if($a['id'] == $b['id']) {
            return 0;
        } else {
            return $a['id'] < $b['id'] ? -1 : 1;
        }
    }
}


Strategy\Context.class.php
<?php
namespace Strategy;

class Context
{
    private $strategy;

    public function __construct($strategy)
    {
        $this->strategy = $strategy;
    }

    public function getCompare($a, $b)
    {
        return $this->strategy->compare($a, $b);
    }
}


Strategy\StrategyTest.php
<?php
spl_autoload_register(function ($className){
    $className = str_replace("\\", "/", $className);
    include $className . ".class.php";
});

use Strategy\IdComparator;
use Strategy\DateComparator;
use Strategy\Context;

$a = array(
    'id' => 1,
    'date' => '2020-05-12'
);

$b = array(
    'id' => 1,
    'date' => '2020-05-13'
);

$strategy = new Context(new IdComparator());
echo $strategy->getCompare($a, $b);
echo "\n";
$strategy = new Context(new DateComparator());
echo $strategy->getCompare($a, $b);
echo "\n";


测试示例:

php Strategy/StrategyTest.php

输出:
0
-1


总结

策略模式将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。通常,策略模式适用于当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。




代码地址:https://github.com/798256478/design-patterns/tree/master/Strategy