天天看点

PHP 设计模式(四):策略模式

什么是策略模式

策略模式(Strategy),又叫算法簇模式,就是定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户。 常见的使用场景比如对象筛选,可以根据日期筛选,也可以根据 ID 筛选;又比如在单元测试中,我们可以在文件和内存存储之间进行切换。

在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。如查找、排序等,一种常用的方法是硬编码(Hard Coding)在一个类中,如需要提供多种查找算法:

  • 可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法;
  • 当然也可以将这些查找算法封装在一个统一的方法中,通过if…else…或者case等条件判断语句来进行选择。

这两种实现方法我们都可以称之为硬编码。

如果需要增加一种新的查找算法,需要修改封装算法类的源代码;更换查找算法,也需要修改客户端调用代码。在这个算法类中封装了大量查找算法,该类代码将较复杂,维护较为困难。如果我们将这些策略包含在客户端,这种做法更不可取,将导致客户端程序庞大而且难以维护,如果存在大量可供选择的算法时问题将变得更加严重。 如何让算法和对象分开来,使得算法可以独立于使用它的客户而变化?为此我们引入策略模式。

应用场景

有多种策略可选择的场景,比如上面说的算法选择,其他如数据库类型、缓存类型、发送验证码方式、支付方式、日志保存类型、队列类型等。

PHP 代码实现

<?php

/**
 * 抽象策略角色
 * Interface RotateItem
 */
interface RotateItem
{
    function inertiaRotate();
    function unInertisRotate();
}

/**
 * 具体策略角色——X产品
 * Class XItem
 */
class XItem implements RotateItem
{
    function inertiaRotate()
    {
        echo "我是X产品,我惯性旋转了。<br/>";
    }

    function unInertisRotate()
    {
        echo "我是X产品,我非惯性旋转了。<br/>";
    }
}

/**
 * 具体策略角色——Y产品
 * Class YItem
 */
class YItem implements RotateItem
{
    function inertiaRotate()
    {
        echo "我是Y产品,我<span style='color: #ff0000;'>不能</span>惯性旋转。<br/>";
    }

    function unInertisRotate()
    {
        echo "我是Y产品,我非惯性旋转了。<br/>";
    }
}

/**
 * 具体策略角色——XY产品
 * Class XYItem
 */
class XYItem implements RotateItem
{
    function inertiaRotate()
    {
        echo "我是XY产品,我惯性旋转。<br/>";
    }

    function unInertisRotate()
    {
        echo "我是XY产品,我非惯性旋转了。<br/>";
    }
}

/**
 * 调用策略--有点像工厂
 * 从这里应该知道每种模式不是独立的,而是多种结合起来灵活使用
 * Class ContextStrategy
 */
class ContextStrategy
{
    private $item;

    function getItem($item_name)
    {
        try
        {
            $class=new ReflectionClass($item_name);
            $this->item=$class->newInstance();
        }
        catch(ReflectionException $e)
        {
            $this->item="";
        }
    }

    function inertiaRotate()
    {
        $this->item->inertiaRotate();
    }

    function unInertisRotate()
    {
        $this->item->unInertisRotate();
    }
}

//=======================调用策略===============================

$strategy = new ContextStrategy();

echo "<span style='color: #ff0000;'>X产品</span><br/>";
$strategy->getItem('XItem');
$strategy->inertiaRotate();
$strategy->unInertisRotate();

echo '<hr>';//横线

echo "<span style='color: #ff0000;'>Y产品</span><br/>";
$strategy->getItem('YItem');
$strategy->inertiaRotate();
$strategy->unInertisRotate();

echo '<hr>';//横线

echo "<span style='color: #ff0000;'>XY产品</span><br/>";
$strategy->getItem('XYItem');
$strategy->inertiaRotate();
$strategy->unInertisRotate();

//结果
//X产品
//我是X产品,我惯性旋转了。
//我是X产品,我非惯性旋转了。
//Y产品
//我是Y产品,我不能惯性旋转。
//我是Y产品,我非惯性旋转了。
//XY产品
//我是XY产品,我惯性旋转。
//我是XY产品,我非惯性旋转了。
           

参考资料:

https://www.jianshu.com/p/9f5ba3e1095d