Skip to content

策略模式属于行为模式的一种,不同于工厂模式工厂模式重点在于创建不同的对象,策略模式的重点在于不同对象的行为。其实现契机为当一个类必须实现同一个接口的不同实现。 策略模式是解决目标问题的一系列实现的集合,在使用上他们之间具有可替换性,而且在使用上他们具有互斥性,这意味着一旦你选择了一个策略实现那么你将不能使用其他的策略实现。

策略模式和工厂模式在结构上表现上有很大的相似性,但是实际的关注点却又有很大的不同,策略模式侧重于对行为的封装使不同的行为具有更强的可替换性,而工厂模式则是对对象的创建。

试想一下你有一个内容审核系统,对于不同的内容你需要使用不同的审核方式去审核。

使用传统的处理方式你的代码可能是这样的:

php
pulic function check($text)
{
    //TODO 一些基础的操作
    if ($text === '文本类型') {
        //TODO 一些特定的需求
        return (new TextContent())->check('文本内容');
    }
    if ($text === '语音类型') {
        //TODO 一些特定的需求
        return (new Voice())->check('文件内容');
    }
    if ($text === '视频类型') {
        //TODO 一些特定的需求
        return (new Video())->check('文件内容');
    }
    //TODO etc...
}

而使用了策略模式的代码是这样的:

php

class Audio
{
    /**
     * @var Content $content
     */
    private $content;

    /**
     * @param Content $content
     * @author yexueduxing
     */
    public function __construct(Content $content)
    {
        $this->content = $content;
    }

    /**
     * 检测
     * @param $content
     * @return mixed
     * @author yexueduxing
     */
    public function check($content)
    {
        return $this->content->check($content);
    }
}

/**
 * 策略类接口
 * Interface Content
 */
interface Content
{
    function check($content);
}

/**
 * 文本检测实现
 * Class TextContent
 */
class TextContent implements Content
{
    public function check($content)
    {
        //todo 使用文本检测方法
        return '文本检测结果';
    }
}

/**
 * 语音检测实现
 * Class voice
 */
class Voice implements Content
{
    public function check($content)
    {
        //todo 使用语音检测方法
        return '语音检测结果';
    }
}

/**
 * 视频检测实现
 * Class Video
 */
class Video implements Content
{
    public function check($content)
    {
        //todo 使用视频检测方法
        return '视频检测结果';
    }
}

//文本检测
$text = new TextContent();
$textResult = (new Auth($text))->check('审核文本');
var_dump($textResult);

//语音检测
$voice = new Voice();
$voiceResult = (new Auth($voice))->check('语音文件');
var_dump($voiceResult);

//视频检测
$video = new Video();
$videoResult = (new Auth($video))->check('视频文件');
var_dump($videoResult);

从代码中不难看出策略模式的有限: 策略模式充分的体现面向对象设计原则中的封装变化、多组合,少继承、针对接口编程等原则。其优点是减少了类之间的耦合性和降低了类修改的复杂度,增加了实现之间的可替换性,对于新增的类型只需要增加一种类型实现即可对于原有的代码没有侵入性的污染。

但是凡事都是有利有弊的: 策略模式的使用使得系统中的类的数量成倍的增加,还有就是对于调用者必须知道系统里有哪些策略模式,以及这些策略的区别然后需要自己去决定调用相对应的策略类。