允许对象在其内部状态更改时更改其行为。该对象似乎将更改其类。
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
对象)在其内部状态更改(在HappyState
,ModerateState
和AngryState
之间切换)时更改其行为(各个状态类中的sayHi()
函数)。