DEV Community

菜皮日记
菜皮日记

Posted on

行为型设计模式-状态 State

简介

跟状态机密切相关。有限状态机 FSM 包含 状态、事件、动作三个元素。

当发生一个事件时,引发老状态变成新状态,并执行一个动作。

状态和行为间一般是有限制的,如某些行为只能再某些状态下进行,某些状态只能触发某些行为。

简单的状态间转换可使用 if else。

更有条理的可以用查表法:二维表中纵向是状态,横向是事件,value则是新状态和动作。做成二维数组配置,事件发生时结合当前状态,组成[老状态][事件]索引去查二维表,得出value是新状态和动作,如果没有value则不变换

再复杂一些之后,可使用状态模式。

角色

  • Context 上下文

    可视为状态机,其内部持有State引用

    可通过改变State的值,来达到改变Context行为的目的

  • 抽象 State

  • 具体 State

类图

如图,Context/Machine中可以changeState来改变当前的状态,其中doThis和doThat签名与State一致,这样看起来就像改变状态的同时,改变了Context的行为。

类图

代码

class Context
{
    private $state;

    public function __construct(State $state)
    {
        $this->transitionTo($state);
    }

    public function transitionTo(State $state): void
    {
        echo "Context: Transition to " . get_class($state) . ".\n";
        $this->state = $state;
        $this->state->setContext($this);
    }

    public function request1(): void
    {
        $this->state->handle1();
    }

    public function request2(): void
    {
        $this->state->handle2();
    }
}
abstract class State
{
    protected $context;

    public function setContext(Context $context)
    {
        $this->context = $context;
    }

    abstract public function handle1(): void;

    abstract public function handle2(): void;
}

class ConcreteStateA extends State
{
    public function handle1(): void
    {
        echo "ConcreteStateA handles request1.\n";
        echo "ConcreteStateA wants to change the state of the context.\n";
        $this->context->transitionTo(new ConcreteStateB());
    }

    public function handle2(): void
    {
        echo "ConcreteStateA handles request2.\n";
    }
}

class ConcreteStateB extends State
{
    public function handle1(): void
    {
        echo "ConcreteStateB handles request1.\n";
    }

    public function handle2(): void
    {
        echo "ConcreteStateB handles request2.\n";
        echo "ConcreteStateB wants to change the state of the context.\n";
        $this->context->transitionTo(new ConcreteStateA());
    }
}

$context = new Context(new ConcreteStateA());
$context->request1();
$context->request2();
Enter fullscreen mode Exit fullscreen mode

output:

Context: Transition to ConcreteStateA.
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.
Context: Transition to ConcreteStateB.
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.
Context: Transition to ConcreteStateA.
Enter fullscreen mode Exit fullscreen mode

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

AWS Q Developer image

Your AI Code Assistant

Generate and update README files, create data-flow diagrams, and keep your project fully documented. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay