状态模式(State)

状态模式是一种行为型设计模式,用于允许一个对象在其内部状态改变时改变其行为,使得对象看起来像是修改了其类。该模式将状态的行为封装在状态对象中,并通过状态对象来控制状态转换,从而使得状态和状态之间的转换变得更加清晰和易于管理。

1. 状态模式的结构

状态模式包含以下几个主要组件:

  • Context(上下文): 维护一个具体的状态对象,并定义与客户端交互的接口。上下文对象可以根据状态对象的变化来改变其行为。
  • State(状态接口): 定义了一个接口,用于具体状态类来实现不同的状态行为。
  • ConcreteState(具体状态): 实现了状态接口中的具体行为,并定义了如何根据当前状态改变上下文的状态。

2. Mermaid 关系图

以下是状态模式的类图,用 Mermaid 表示:

classDiagram
    class Context {
        - state : State
        + request() : void
        + setState(state : State) : void
    }

    class State {
        + handle(context : Context) : void
    }

    class ConcreteStateA {
        + handle(context : Context) : void
    }

    class ConcreteStateB {
        + handle(context : Context) : void
    }

    Context --> State : "使用"
    State <|-- ConcreteStateA
    State <|-- ConcreteStateB
    ConcreteStateA --> Context : "改变"
    ConcreteStateB --> Context : "改变"

3. 状态模式的实现

State 状态接口:

class Context;

class State {
public:
    virtual ~State() = default;
    virtual void handle(Context* context) = 0;
};

ConcreteStateA 具体状态A:

#include <iostream>

class ConcreteStateA : public State {
public:
    void handle(Context* context) override;
};

ConcreteStateB 具体状态B:

#include <iostream>

class ConcreteStateB : public State {
public:
    void handle(Context* context) override;
};

Context 上下文:

class Context {
private:
    State* state;

public:
    Context(State* state) : state(state) {}

    void setState(State* newState) {
        state = newState;
    }

    void request() {
        state->handle(this);
    }
};

具体状态的实现:

ConcreteStateA 具体状态A的实现:

void ConcreteStateA::handle(Context* context) {
    std::cout << "Handling request in ConcreteStateA" << std::endl;
    // Change state
    context->setState(new ConcreteStateB());
}

ConcreteStateB 具体状态B的实现:

void ConcreteStateB::handle(Context* context) {
    std::cout << "Handling request in ConcreteStateB" << std::endl;
    // Change state
    context->setState(new ConcreteStateA());
}

Client 客户端代码:

int main() {
    ConcreteStateA* stateA = new ConcreteStateA();
    ConcreteStateB* stateB = new ConcreteStateB();
    
    Context* context = new Context(stateA);
    
    context->request();
    context->request();
    
    delete stateA;
    delete stateB;
    delete context;

    return 0;
}

4. 使用状态模式

在客户端代码中,创建具体状态对象,并将其设置为上下文的当前状态。调用上下文的 request() 方法时,状态对象会执行相应的处理,并可能改变上下文的状态。每次请求都会根据当前状态执行不同的操作,并自动切换到新的状态。

5. 总结

状态模式通过将状态的行为封装在状态对象中,使得状态之间的转换变得更加清晰和可管理。通过状态对象来控制上下文的行为,使得状态的切换变得更加自然和灵活。Mermaid 类图展示了上下文、状态接口、具体状态类以及它们之间的关系,帮助理解模式的结构和实现。