【深入PHP 面向对象】读书笔记(十二) - 执行及描述任务(二) - 策略模式

11.2 策略模式

11.2.1 问题

我们继续之前的例子,之前的例子实现了自动判断答案正确性的功能,现在需要一个「添加问题」的功能,因此我们创建一个 Question 类,并为其添加 mark() 方法。

现在假设用户回答问题时可以使用多种不同的标记方式,比如支持MarkLogic语音、直接匹配以及正则表达式这 3 种标记方式。我们该如何实现呢?

最简单的处理方式就是通过继承来让子类实现这些差异。

这里写图片描述

如果只考虑这一方面的变化,这样做能适应我们的需求。但是,如果我们被要求支持不同类型的问题(基于文本的问题和基于多媒体的问题),则我们的继承树就会从两层变成三层:

这里写图片描述

这样做不仅导致了需要在体系汇总创建大量的类,而且还会导致代码的重复。

11.2.2 实现

当类必须支持同一个接口的多种实现时,最好的方法是提取出这些实现,并将它们放在自己的类型中,而不是通过继承原有的类去支持这些实现。

因此,我们将标记方式 Marker类 抽取出来:

这里写图片描述

下面是 Question 类及其子类的代码:

/* 抽象Question类 */
abstract class Question {
    protected $prompt;
    protected $marker;

    function __construct($prompt, Marker $marker) {
        $this->prompt = $prompt;
        $this->marker = $marker;
    }

    function mark($response) {
        return $this->marker->mark($response);
    }
}

/* TextQuestion文本问题类 */
class TextQuestion extends Question {
    // 处理文本问题特有的操作
}
/* AVQuestion多媒体类 */
class AVQuestion extends Question {
    // 处理语音问题特有的操作
}

Question抽象类定义基本的功能,保存了一个$prompt属性和一个Marker对象。具体的处理能力交给子类(TextQuestion文本问题类、AVQuestion多媒体类)实现。

当 Question::mark() 使用终端用户的响应作为参数时,mark() 方法之委托 Marker对象来解决问题。

接下来我们再来定义 Marker 对象,这里我们关注结构设计,简单处理实现细节:


abstract class Marker {
    protected $test;

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

    abstract function mark($response);
}

class MarkLogicMarker extends Marker {
    function mark($response) {
        return true;
    }
}
class MatchMarker extends Marker {
    function mark($response) {
        return $this->test == $response;
    }
}
class RegexpMarker extends Marker {
    function mark($response) {
        return preg_match($this->test, $response);
    }
}

至此,我们可以在客户端做一个演示代码:

/* 三种情况下的正确答案规则 */
$markers = array(
    new RegexpMarker('/five/'),
    new MatchMarker('five'),
    new MarkLogicMarker('$input equals "five"')
);

foreach ($markers as $marker) {
    /* 对于每一种答案规则下,进行问题设置 */
    $question = new TextQuestion("Guess a number", $marker);
    /* 模拟两个答案'four','five'来验证 */
    foreach (array('four','five') as $response) {
        if ($question->mark($response)) {
            echo "true";
        } else {
            echo "false";
        }
    }
}

输入'four'的答案,得到 false;输入'five'的答案,会得到 true。(MarkLogicMarker 这个类的逻辑处理需要结合上一章节的内容,这里直接输出 true)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值