状态模式

<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
```