行为型设计模式-状态 State
date
Apr 25, 2021
slug
design-pattern-state
status
Published
tags
设计模式
summary
type
Page
简介
跟状态机密切相关。有限状态机 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();
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.