专栏首页Lemon黄PHP设计模式——状态模式

PHP设计模式——状态模式

允许对象在其内部状态更改时更改其行为。该对象似乎将更改其类。

John在一家受欢迎的电话支持公司中担任客户支持代表。在以客户服务为导向的公司中,公司的首要任务是确保客户满意。为了改善服务质量,该公司投入了大量资金来改善支持代表的服务。最近的研究表明,支持代表的情绪会影响他们在工作中的表现。John本人承认,接听电话时的前几句话通常可以表明他所处的心情。当他心情愉快时,通常会向顾客打招呼“嗨!”或“你好,怎么样”。我可以帮您吗?”当他生气且情绪低落时,他的回答是打招呼“你好”或“是?”。如果John情绪温和,则他将用“嗨”或“你好”柔和的和一个人打开对话。

让我们将以上的信息放入代码中:

class SupportRep
{
    private $_state =  "happy";
    public function setState($state)
    {
        $this->_state = $state;
    }
 
    public function sayHi()
    {
        if ($this->_state=='happy') {
            echo 'hi there!';
        } else if ($this->_state=='angry') {
            echo 'yes?';
        } else if ($this->_state=='moderate') {
            echo 'hi';
        }
    }
}

上面的代码非常简单明了,可以帮助我们研究支持代表的行为。但是,随着研究的进展和更多信息的引入,该代码可能还不够。研究表明,一个人的情绪会根据他打过的电话的数量以及当前的情绪而改变。

当John接听五到十个电话时,他的心情将从“快乐”变为“温和”,这可能是因为他感到疲倦或承受着压力。如果他接到10个以上的电话,他的心情将从“温和”变为“愤怒”,处理太多的支持电话确实很麻烦。

让我们重新编写代码以添加以上的逻辑:

class SupportRep
{
    private $_state =  null;
    public  $numOfCalls = 0;
    public function setState($state)
    {
        $this->_state = $state;
    }
 
    public function sayHi()
    {
        if ($this->_state=='happy') {
            echo 'hi there!';
            if ($this->numOfCalls>5&&$this->numOfCalls<10) {
                $this->setState('moderate');
            }
            if ($this->numOfCalls>10) {
                $this->setState('angry');
            }
        } else if ($this->_state=='angry') {
            echo 'yes?';
        } else if ($this->_state=='moderate') {
            echo 'hi';
            if ($this->numOfCalls>10) {
                $this->setState('angry');
            }
        }
        $this->numOfCalls;
    }
}

你发现上面的代码有什么问题吗?不,它没有什么错,除了一堆的if-else的语句。对于我们来说,它甚至看起来都不是面向对象的,最糟糕的是它明显违反了单一责任原则(SRP)。此类更改的原因有多种。当你对快乐状态,温和状态或愤怒状态有其他逻辑时。它引入了代码修改,并且记住我们在这里只是在谈论sayHi()函数。当基于情绪的条件适用于其他岗位的各个方面时,会发生什么?

是时候改变了。在这种情况下,我们就需要使用状态模式(State Pattern)。状态模式使我们可以封装变化的部分,即sayHi函数。具体取决于支持代表的心情。

首先,让我们创建一个状态接口(StateInterface),所有后续状态都必须实现它:

interface StateInterface
{
   public function sayHi();
}

然后,我们将创建三个状态的类,每个类都实现自己的逻辑:

class AngryState implements StateInterface
{
    private $_supportRep = null;
    public function __construct(SupportRep $supportRep)
    {
        $this->_supportRep = $supportRep;
    }
    public function sayHi()
    {
        echo 'yes?';
    }
}
 
class ModerateState implements StateInterface
{
    private $_supportRep = null;
    public function __construct(SupportRep $supportRep)
    {
        $this->_supportRep = $supportRep;
    }
    public function sayHi() {
        echo 'hi';
        if ($this->_supportRep->numOfCalls>10) {
            $this->_supportRep->setState(new AngryState($this->_supportRep
        ));
        }
    }
}
 
class HappyState implements StateInterface
{
    private $_supportRep = null;
    public function __construct(SupportRep $supportRep)
    {
        $this->_supportRep = $supportRep;
    }
 
    public function sayHi()
    {
        echo 'hi there!';
        if ($this->_supportRep->numOfCalls>5&&$this->_supportRep->numOfCalls<10) {
        Rep));
    ));
    }
}

最后,我们来重构下支持代表的类SupportRep

class SupportRep
{
    private $_state =  null;
    public  $numOfCalls = 0;
    public function __construct()
    {
        $this->_state = new ModerateState($this);
    }
 
    public function setState($state)
    {
        $this->_state = $state;
    }
 
    public function sayHi()
    {
        $this->_state->sayHi();
        $this->numOfCalls++;
    }
}

如你所见,SupportRep类的sayHi()函数将其职责委托给状态类。它不再违反单一责任原则(SRP)。三个状态类仍然可以通过组合来更改主要类的状态。

现在,SupportRep变得更加整洁,如果需要添加任何其他逻辑,则可以将其作为单独的状态类来完成。 SupportRep的其他功能可以委托给状态类。

在我们的示例中,状态模式允许对象(SupportRep对象)在其内部状态更改(在HappyStateModerateStateAngryState之间切换)时更改其行为(各个状态类中的sayHi()函数)。

本文分享自微信公众号 - Lemon黄(lemonhunag),作者:Lemon黄

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • PHP设计模式——抽象方法

    Dragon公司的业务受到轰炸,而CEO希望特许所有海外分支机构的专营权。他首先要注意的问题是如何确保产品质量。他们不希望特许经营者削减成本和使用低质量的组件。...

    Lemon黄
  • 通俗易懂PHP基础【9-类和对象(1)】

    曾经见过一个摄影师喂藏羚羊喝水,同行的警察把藏羚羊赶走了,摄影师问为什么,警察说,要不然它会以为人类是善良的。

    Lemon黄
  • PHP设计模式——模板方法

    管理公司员工的日常行程可能是一项耗时的工作。如果可以使用程序将日常任务编程为自动发生,那将容易得多。Mark在Yahaa Inc工作了四年, 他是一名程序员,他...

    Lemon黄
  • 深入理解this,bind、call

    mcq
  • vue + iview/elementUi --城市多选

    最近收到了一个需求,管理系统需要上线一个活动,但是活动是根据地区上线的,最小范围到市,于是有了下面这个组件 页面展示如图:

    super.x
  • 面向对象版tab 栏切换案例

    梨涡浅笑
  • element表单校验问题

    新增时,校验为空未通过,点击取消按钮。重新打开编辑,明明有值,显示校验未通过。

    崔笑颜
  • React 深入系列5:事件处理

    iKcamp
  • Vue 绑定简单分析实现

    使用js es6 中 Object.defineProperty为我们自己定义的VM创建示例。同时这个方法通过提供了set.get方法的触发我们的监听事件。

    deep_sadness
  • 基于 Vue 的商品主图放大镜方案

    在做电商类应用时,难免会遇到商品主图实现放大镜效果的场景,现有的基于Vue的第三方包不多并且无法直接复用,今天,我来分享一种高稳定性的基于 Vue 的图片放大镜...

    政采云前端团队

扫码关注云+社区

领取腾讯云代金券