状态【State】

实例

abstract class State
{
    abstract public function writeProgram(Work $emergency);
}
class Work
{
    private $current, $hour, $isFinish = false;
    public function __construct(State $current)
    {
        $this->setCurrent($current);
    }
    public function getCurrent()
    {
        return $this->current;
    }
    public function setCurrent($current)
    {
        $this->current = $current;
    }
    public function getHour()
    {
        return $this->hour;
    }
    public function setHour($hour)
    {
        $this->hour = $hour;
    }
    public function isFinish(): bool
    {
        return $this->isFinish;
    }
    public function setIsFinish(bool $isFinish)
    {
        $this->isFinish = $isFinish;
    }
    public function writeProgram()
    {
        $this->current->writeProgram($this);
    }
}

class ForeNoonState extends State
{
    public function writeProgram(Work $emergency)
    {
        if (9 <= $emergency->getHour() && $emergency->getHour() < 12) {
            echo $emergency->getHour(), '点 精神饱满', PHP_EOL;
        } else {
            $emergency->setCurrent(new NoonState());
            $emergency->writeProgram();
        }
    }
}
class NoonState extends State
{
    public function writeProgram(Work $emergency)
    {
        if (12 <= $emergency->getHour() && $emergency->getHour() < 13) {
            echo $emergency->getHour(), '点 饥肠辘辘', PHP_EOL;
        } else {
            $emergency->setCurrent(new AfterNoonState());
            $emergency->writeProgram();
        }
    }
}
class AfterNoonState extends State
{
    public function writeProgram(Work $emergency)
    {
        if (13 <= $emergency->getHour() && $emergency->getHour() < 18) {
            echo $emergency->getHour(), '点 状态不错', PHP_EOL;
        } else {
            $emergency->setCurrent(new EveningState());
            $emergency->writeProgram();
        }
    }
}
class EveningState extends State
{
    public function writeProgram(Work $emergency)
    {
        if ($emergency->isFinish()) {
            $emergency->setCurrent(new RestState());
            $emergency->writeProgram();
        } else {
            if (18 <= $emergency->getHour() && $emergency->getHour() < 21) {
                echo $emergency->getHour(), '点 身心疲惫', PHP_EOL;
            } else {
                $emergency->setCurrent(new SleepState());
                $emergency->writeProgram();
            }
        }
    }
}
class SleepState extends State
{
    public function writeProgram(Work $emergency)
    {
        echo $emergency->getHour(), '点 睡觉', PHP_EOL;
    }
}
class RestState extends State
{
    public function writeProgram(Work $emergency)
    {
        echo $emergency->getHour(), '点 下班休息', PHP_EOL;
    }
}
echo '==加班状态===', PHP_EOL;
$emergency = new Work(new ForeNoonState());
$emergency->setHour(9);
$emergency->writeProgram();

$emergency->setHour(12);
$emergency->writeProgram();

$emergency->setHour(15);
$emergency->writeProgram();

$emergency->setHour(18);
$emergency->writeProgram();

$emergency->setHour(21);
$emergency->writeProgram();
echo '==准点下班状态===', PHP_EOL;
$emergency = new Work(new ForeNoonState());
$emergency->setHour(9);
$emergency->writeProgram();

$emergency->setHour(12);
$emergency->writeProgram();

$emergency->setHour(15);
$emergency->writeProgram();

$emergency->setIsFinish(true);

$emergency->setHour(18);
$emergency->writeProgram();
/*
==加班状态===
9点 精神饱满
12点 饥肠辘辘
15点 状态不错
18点 身心疲惫
21点 睡觉
==准点下班状态===
9点 精神饱满
12点 饥肠辘辘
15点 状态不错
18点 下班休息
*/

总结

状态模式通过将对象的每一种状态封装为独立的类,并在环境对象中持有当前状态的引用,实现了行为随内部状态动态切换的目的,从而消除大量的条件判断语句。

意图

允许对象在内部状态发生改变时,改变其行为,使对象看起来好像修改了它的类。

主要解决

消除代码中包含大量与对象状态有关的条件语句(如 if...elseswitch),实现行为随状态改变而改变。

何时使用

代码中包含大量与对象状态有关的条件语句。

如何解决

将每一种具体状态抽象出来成为独立的状态类,并在环境对象(Context) 中持有当前状态的引用。环境对象将行为委托给当前状态对象执行。

关键代码

状态转换逻辑与状态对象自身合成一体,而非集中在巨大的条件语句块中。

优点

缺点

使用场景

注意事项

状态数量不宜过多(建议不超过 5 个),否则结构会过于复杂。