定義
允許一個物件在其內部狀態改變時改變它的行為,物件看起來似乎修改了它的類。
設計的原則和思想
- 解耦的是物件和狀態。
- 不變部分是物件,變化部分是狀態。
- 核心思想是不同狀態下做的事情也不同。
一句話概括設計模式
物件的狀態改變,行為也要隨之改變。
結構中包含的角色
- Context(環境類)
- State(抽象狀態類)
- 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();
優點
- 狀態物件可以共享,從而減少系統物件的個數。
- 可以簡化條件語句上下文的程式碼。
- 可以對狀態轉換程式碼進行集中管理。
缺點
- 系統中類和物件的個數會增加,導致系統執行開銷增大。
- 狀態模式的結構與實現都較為複雜,增加系統設計的難度。
- 增加新的狀態類需要修改負責狀態轉換的相關程式碼。
- 如果狀態太少,反而顯得臃腫。
何時使用
- 物件的行為依賴於它的狀態,狀態的改變將導致行為的變化。
- 在程式碼中包含大量與物件狀態有關的條件語句。
- 當不同狀態和基於條件的狀態轉換中存在許多重複程式碼時。
實際應用場景
- 訂單狀態切換。
- 遊戲角色升級。
- 工作流。
- QQ現在的狀態,線上,隱身,忙碌。
有限狀態機
有限狀態機,也稱為FSM(Finite State Machine),其在任意時刻都處於有限狀態集合中的某一狀態。
FSM是一種演算法思想,簡單而言,有限狀態機由一組狀態、一個初始狀態、輸入和根據輸入及現有狀態轉換為下一個狀態的轉換函式組成。
狀態機可歸納為4個要素,即現態、條件、動作、次態。詳解如下。
現態 : 是指當前所處的狀態。
條件 : 又稱為“事件”。當一個條件被滿足,將會觸發一個動作,或者執行一次狀態的遷移。
動作 : 條件滿足後執行的動作。動作執行完畢後,可以遷移到新的狀態,也可以仍舊保持原狀態。動作不是必需的,當條件滿足後,也可以不執行任何動作,直接遷移到新狀態。
次態 : 條件滿足後要遷往的新狀態。
結構中包含的角色
- State(狀態類)
- Event(事件/條件類)
- AbstractTransition (抽象動作類)
- ConcreteTransition (具體動作類)
- AbstractStateMachine (抽象狀態機)
- 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();
本作品採用《CC 協議》,轉載必須註明作者和本文連結