极简设计模式-状态模式

PHP技术
395
0
0
2022-08-04

状态模式 - State Pattern

定义

允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

设计的原则和思想

  1. 解耦的是对象和状态。
  2. 不变部分是对象,变化部分是状态。
  3. 核心思想是不同状态下做的事情也不同。

一句话概括设计模式

对象的状态改变,行为也要随之改变。

结构中包含的角色

  1. Context(环境类)
  2. State(抽象状态类)
  3. ConcreteState(具体状态类)

最小可表达代码

abstract class State
{  
    public abstract function handle();  
}

class ConcreteState extends State
{  
    public function handle()
    {
        echo '具体状态';
    }
}

class Context
{
    private $state;

    public function setState(State $state)
    {  
        $this->state = $state;  
    }

    public function request()
    {  
        $this->state->handle();
    }  
}

$context = new Context();
$context->setState(new ConcreteState());
$context->request();

优点

  1. 状态对象可以共享,从而减少系统对象的个数。
  2. 可以简化条件语句上下文的代码。
  3. 可以对状态转换代码进行集中管理。

缺点

  1. 系统中类和对象的个数会增加,导致系统运行开销增大。
  2. 状态模式的结构与实现都较为复杂,增加系统设计的难度。
  3. 增加新的状态类需要修改负责状态转换的相关代码。
  4. 如果状态太少,反而显得臃肿。

何时使用

  1. 对象的行为依赖于它的状态,状态的改变将导致行为的变化。
  2. 在代码中包含大量与对象状态有关的条件语句。
  3. 当不同状态和基于条件的状态转换中存在许多重复代码时。

实际应用场景

  1. 订单状态切换。
  2. 游戏角色升级。
  3. 工作流。
  4. QQ现在的状态,在线,隐身,忙碌。

有限状态机

    有限状态机,也称为FSM(Finite State Machine),其在任意时刻都处于有限状态集合中的某一状态。
    FSM是一种算法思想,简单而言,有限状态机由一组状态、一个初始状态、输入和根据输入及现有状态转换为下一个状态的转换函数组成。
    状态机可归纳为4个要素,即现态、条件、动作、次态。详解如下。
    现态 : 是指当前所处的状态。
    条件 : 又称为“事件”。当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
    动作 : 条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
    次态 : 条件满足后要迁往的新状态。

结构中包含的角色

  1. State(状态类)
  2. Event(事件/条件类)
  3. AbstractTransition (抽象动作类)
  4. ConcreteTransition (具体动作类)
  5. AbstractStateMachine (抽象状态机)
  6. ConcreteStateMachine (具体状态机)

有限状态机管理状态的代码

// 状态
class State
{
    private $stateCode;

    public function __construct(String $stateCode)
    {
        $this->stateCode = $stateCode;

    }

    public function getStateCode()
    {
        return $this->stateCode;
    }
}

// 事件
class Event
{
    private $eventCode;
    private $parameters = [];

    public function __construct(String $eventCode,  array $parameters = [])
    {
        $this->eventCode = $eventCode;
        $this->parameters = $parameters;
    }

    public function getEventCode()
    {
        return $this->eventCode;
    }

    public function getParameters() : array{
        return $this->parameters;
    }
}

// 抽象动作
abstract class AbstractTransition
{
    protected $currentState; // 现态  
    protected $nextState; // 次态

    public function __construct(State $currentState, State $nextState)
    {
        $this->currentState = $currentState;
        $this->nextState = $nextState;
    }

    // 具体动作需要执行的方法  
    protected abstract function subHandle(Event $event) : bool;

    // 定义动作执行的方法  
    public function handle(Event $event)
    {
        if ($this->subHandle($event)) {
            return $this->nextState;
        }

        echo 'throw new Exception 抛错';
    }
}

// 抽象状态机
abstract class AbstractStateMachine
{
    protected abstract function getStateEventTransitionMap() : array;

    protected function getTransition(String $stateCode, String $eventCode)
    {
        $stateEventTransitionMap = $this->getStateEventTransitionMap();

        $eventTransitionMap = $stateEventTransitionMap[$stateCode] ?? [];

        $transition = $eventTransitionMap[$eventCode] ?? [];

        return $transition;
    }

    public  function handle(String $stateCode, Event $event)
    {
        $eventCode = $event->getEventCode();

        if ($transition = $this->getTransition($stateCode, $eventCode)) {
            return $transition->handle($event);
        }

        echo 'throw new Exception 抛错';
    }
}

// 订单事件编码
class OrderEventCode {
    const PAY = "支付订单";
    const CANCEL = "取消订单";
}

// 订单状态编码
class OrderStateCode {
    const UNPAID = "待支付";
    const PAID = "已支付";
    const CANCELED = "已取消";
}

// 支付动作
class PayTransition extends AbstractTransition
{
    protected function subHandle(Event $event) : bool{
        var_dump('支付订单', $event->getParameters());
        return true;
    }
}

// 订单状态机
class OrderStateMachine extends AbstractStateMachine
{
    public function getStateEventTransitionMap() : array{
        return [
            OrderStateCode::UNPAID => [
                OrderEventCode::PAY => new PayTransition(
                    new State(OrderStateCode::UNPAID), new State(OrderStateCode::PAID)
                ),
            ],
        ];
    }

    public function pay()
    {
        $event = new Event(OrderEventCode::PAY, ['order_id' => 1]);

        $this->handle(OrderStateCode::UNPAID, $event);
    }
}

// 支付
$stateMachine = new OrderStateMachine();
$stateMachine->pay();