狀態模式

<image>

狀態模式（state pattern），是一種行為類型的軟體設計模式，它可以讓物件在其內部狀態有變化時，改變其行為。這種模式有點像有限狀態機的概念。狀態模式可以被當成成一種策略模式，它能夠通過在調用模式介面中所定義的方法來切換策略。

狀態模式在電腦編程中的用途，是基於其內部狀態，將同一物件的各種有不同行為進行封裝。對於物件來說，這是可以在運行時更改其行為的一種更為簡潔方式，它無需訴諸條件語句而從而提高了可維護性。

## 概述

狀態設計模式是《設計模式：可復用物件導向軟體的基礎》所收錄的二十三個模式之一，本書描述了如何解決常見的設計問題。此類問題涵蓋了靈活且可重用的面向對象軟體的設計，例如易於實現、更改、測試和重用的對象。

狀態模式常用來解決兩個主要問題：

- 當對象的內部狀態改變時，它的行為也應該改變。
- 應獨立定義特定於狀態的行為。也就是說，添加新狀態不應影響現有狀態的行為。

在類中為特定狀態直接實作行為是不夠彈性的，因為它將類與特定行為綁定，這將使得在獨立於這個類，不更改這個類的情況下，無法增加新的狀態或改變狀態的行為。因此，此模式描述了兩種解決方案：

- 定義單獨的（狀態）物件，為每個狀態封裝特定於裝態的行為。亦即，定義一個介面（狀態）以用於執行特定於狀態的行為，並為每種狀態定義一個實現該接口的類。
- 類將特定於狀態的行為委託給它的當前戕態物件，而不直接實現特定於狀態的行為。

這使得類與特定於狀態的行為如何實作獨立開來。新的狀態可以通過定義新的狀態類來實現。類可以在運行時，藉由改變當前狀態物件來改變其行為。

## 結構

<image>

在隨附的統一建模語言（UML）類圖中， `Context` 類不直接實現特定於狀態的行為。相反，`Context`通過`State`介面來執行特定於狀態的行為（`state.handle()`），這使得`Context`獨立於特定於狀態行為的實現方式。`ConcreteStateA`和`ConcreteStateB`類實現`State`介面，即為每個狀態實現（封裝）特定於狀態的行為。UML序列圖說明了運行時互動：

`Context`對象將特定於狀態的行為委託給不同的`State`對象。首次時，`Context`調用`handle(this)`時，這基於了其當前（初始）狀態（`ConcreteStateA`），此時執行操作並調用 `Context.setState(ConcreteStateB)`來將當前狀態更改為`ConcreteStateB`。下一次時，`Context`再次調用`handle(this)`，這基於了其當前狀態對象（`ConcreteStateB`），此時執行操作並將當前狀態更改為`ConcreteStateA`。

## 示例

### C++

下面是C++例子：

```cpp
import std;

using std::shared_ptr;

// Abstract State
class FanState {
public:
    virtual void handleButtonPress(class Fan& fan) const = 0;
    virtual ~FanState() = default;
};

// Context
class Fan {
private:
    shared_ptr<FanState> currentState;
public:
    explicit Fan(shared_ptr<FanState> state):
        currentState{state} {}

    void setState(shared_ptr<FanState> state) noexcept {
        currentState = state;
    }

    void pressButton() noexcept {
        currentState->handleButtonPress(*this);
    }
};

// Concrete States
class OffState : public FanState {
public:
    void handleButtonPress(Fan& fan) const override {
        std::println("Fan is OFF -> Switching to LOW speed.");
        fan.setState(std::make_shared<LowSpeedState>());
    }
};

class LowSpeedState : public FanState {
public:
    void handleButtonPress(Fan& fan) const override {
        std::println("Fan is on LOW speed -> Switching to HIGH speed.");
        fan.setState(make_shared<HighSpeedState>());
    }
};

class HighSpeedState : public FanState {
public:
    void handleButtonPress(Fan& fan) const override {
        std::println("Fan is on HIGH speed -> Turning OFF.");
        fan.setState(make_shared<OffState>());
    }
};

int main() {
    Fan fan(std::make_shared<OffState>());

    // Simulate pressing the button several times
    fan.pressButton(); // OFF -> LOW
    fan.pressButton(); // LOW -> HIGH
    fan.pressButton(); // HIGH -> OFF
    fan.pressButton(); // OFF -> LOW

    return 0;
}
```

### Python

下面是Python的例子：

```python
from abc import ABC, abstractmethod

class State(ABC):
    @abstractmethod
    def __call__(self): pass

class ConcreteStateA(State):
    def __call__(self): 
        print("Called ConcreteStateA handle method")

class ConcreteStateB(State):
    def __call__(self): 
        print("Called ConcreteStateB handle method")

class Context():
    def __init__(self, state):
        self.state = state
    def set_state(self, state):
        self.state = state
    def __call__(self):
        self.state()
```

其執行：

```pycon
>>> state1 = ConcreteStateA()
>>> context = Context(state1)
>>> context()
Called ConcreteStateA handle method
>>> state2 = ConcreteStateB()
>>> context.set_state(state2)
>>> context()
Called ConcreteStateB handle method
```