14.C++设计模式-状态模式

第一部分:基础概念与实现

一、概念定义

状态模式(State Pattern)是一种行为型设计模式,它允许对象在其内部状态改变时改变它的行为,看起来就像是改变了它的类一样。

核心思想:将状态相关的行为封装在独立的状态类中,并将状态切换逻辑从主对象中分离出来。

二、模式结构

可能改变状态
可能改变状态
Context
-State* state
+request()
+setState(State* state)
<<abstract>>
State
+handle(Context* context)
ConcreteStateA
+handle(Context* context)
ConcreteStateB
+handle(Context* context)

三、核心角色

  1. Context(环境类):维护一个State实例,定义当前状态
  2. State(抽象状态类):定义一个接口封装与特定状态相关的行为
  3. ConcreteState(具体状态类):实现抽象状态接口的具体行为

四、应用场景

适用场景

  1. 对象的行为依赖其状态,并且运行时状态会改变
  2. 有大量的条件语句(if-else或switch-case)依赖于对象状态
  3. 状态转换逻辑复杂,需要显式管理
  4. 多个状态共享相同的行为,通过继承复用代码

实际案例

  • 订单状态(待支付、已支付、已发货、已完成、已取消)
  • 电梯状态(运行、停止、维修、故障)
  • TCP连接状态(已建立、监听、关闭)
  • 游戏角色状态(站立、奔跑、跳跃、游泳、死亡)
  • 工作流审批状态

五、C++代码示例

示例1:电梯系统

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>

using namespace std;

// 前向声明
class ElevatorContext;

// 抽象状态类
class ElevatorState {
public:
    virtual ~ElevatorState() = default;
    virtual void openDoor(ElevatorContext* context) = 0;
    virtual void closeDoor(ElevatorContext* context) = 0;
    virtual void run(ElevatorContext* context) = 0;
    virtual void stop(ElevatorContext* context) = 0;
    virtual string getStateName() = 0;
};

// 环境类
class ElevatorContext {
private:
    unique_ptr<ElevatorState> currentState;
    
public:
    ElevatorContext(unique_ptr<ElevatorState> initialState) 
        : currentState(move(initialState)) {}
    
    void setState(unique_ptr<ElevatorState> state) {
        currentState = move(state);
        cout << "电梯状态变为: " << currentState->getStateName() << endl;
    }
    
    void openDoor() {
        currentState->openDoor(this);
    }
    
    void closeDoor() {
        currentState->closeDoor(this);
    }
    
    void run() {
        currentState->run(this);
    }
    
    void stop() {
        currentState->stop(this);
    }
};

// 具体状态类:停止状态
class StopState : public ElevatorState {
public:
    void openDoor(ElevatorContext* context) override {
        cout << "电梯已停止,可以开门" << endl;
        // 转换到开门状态
        // context->setState(make_unique<OpenState>());
    }
    
    void closeDoor(ElevatorContext* context) override {
        cout << "电梯门已关闭" << endl;
    }
    
    void run(ElevatorContext* context) override {
        cout << "电梯开始运行" << endl;
        // 转换到运行状态
        // context->setState(make_unique<RunState>());
    }
    
    void stop(ElevatorContext* context) override {
        cout << "电梯已经处于停止状态" << endl;
    }
    
    string getStateName() override {
        return "停止状态";
    }
};

// 运行状态
class RunState : public ElevatorState {
public:
    void openDoor(ElevatorContext* context) override {
        cout << "电梯运行时不能开门!" << endl;
    }
    
    void closeDoor(ElevatorContext* context) override {
        cout << "电梯门已关闭,继续运行" << endl;
    }
    
    void run(ElevatorContext* context) override {
        cout << "电梯正在运行中" << endl;
    }
    
    void stop(ElevatorContext* context) override {
        cout << "电梯停止运行" << endl;
        context->setState(make_unique<StopState>());
    }
    
    string getStateName() override {
        return "运行状态";
    }
};

// 使用示例
int main() {
    // 初始状态为停止状态
    auto elevator = make_unique<ElevatorContext>(make_unique<StopState>());
    
    elevator->run();      // 尝试运行
    elevator->stop();     // 停止
    elevator->openDoor(); // 开门
    elevator->closeDoor();// 关门
    
    return 0;
}

示例2:订单状态机(完整示例)

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>
#include <map>
#include <functional>

using namespace std;

class OrderContext;

// 订单状态枚举
enum class OrderStateType {
    PENDING,    // 待支付
    PAID,       // 已支付
    SHIPPED,    // 已发货
    DELIVERED,  // 已送达
    CANCELLED   // 已取消
};

// 抽象状态类
class OrderState {
public:
    virtual ~OrderState() = default;
    
    virtual void pay(OrderContext* context) = 0;
    virtual void ship(OrderContext* context) = 0;
    virtual void deliver(OrderContext* context) = 0;
    virtual void cancel(OrderContext* context) = 0;
    virtual OrderStateType getType() const = 0;
    virtual string getDescription() const = 0;
};

// 环境类
class OrderContext {
private:
    unique_ptr<OrderState> currentState;
    map<string, string> orderInfo;
    
public:
    OrderContext(unique_ptr<OrderState> initialState) 
        : currentState(move(initialState)) {}
    
    void setState(unique_ptr<OrderState> state) {
        currentState = move(state);
        cout << "订单状态变更为: " << currentState->getDescription() << endl;
    }
    
    OrderStateType getCurrentStateType() const {
        return currentState->getType();
    }
    
    void pay() {
        cout << "执行支付操作..." << endl;
        currentState->pay(this);
    }
    
    void ship() {
        cout << "执行发货操作..." << endl;
        currentState->ship(this);
    }
    
    void deliver() {
        cout << "执行送达操作..." << endl;
        currentState->deliver(this);
    }
    
    void cancel() {
        cout << "执行取消操作..." << endl;
        currentState->cancel(this);
    }
    
    void setOrderInfo(const string& key, const string& value) {
        orderInfo[key] = value;
    }
    
    string getOrderInfo(const string& key) const {
        auto it = orderInfo.find(key);
        return it != orderInfo.end() ? it->second : "";
    }
};

// 待支付状态
class PendingState : public OrderState {
public:
    void pay(OrderContext* context) override {
        cout << "支付成功,订单状态变为已支付" << endl;
        // 这里可以调用外部支付接口
        context->setState(make_unique<PaidState>());
    }
    
    void ship(OrderContext* context) override {
        cout << "错误:订单未支付,不能发货" << endl;
    }
    
    void deliver(OrderContext* context) override {
        cout << "错误:订单未支付,不能确认送达" << endl;
    }
    
    void cancel(OrderContext* context) override {
        cout << "订单已取消" << endl;
        context->setState(make_unique<CancelledState>());
    }
    
    OrderStateType getType() const override {
        return OrderStateType::PENDING;
    }
    
    string getDescription() const override {
        return "待支付";
    }
};

// 已支付状态
class PaidState : public OrderState {
public:
    void pay(OrderContext* context) override {
        cout << "错误:订单已支付,不能重复支付" << endl;
    }
    
    void ship(OrderContext* context) override {
        cout << "订单已发货" << endl;
        context->setState(make_unique<ShippedState>());
    }
    
    void deliver(OrderContext* context) override {
        cout << "错误:订单未发货,不能确认送达" << endl;
    }
    
    void cancel(OrderContext* context) override {
        cout << "订单已取消,将发起退款" << endl;
        context->setState(make_unique<CancelledState>());
    }
    
    OrderStateType getType() const override {
        return OrderStateType::PAID;
    }
    
    string getDescription() const override {
        return "已支付";
    }
};

// 已发货状态
class ShippedState : public OrderState {
public:
    void pay(OrderContext* context) override {
        cout << "错误:订单已发货,不能重复支付" << endl;
    }
    
    void ship(OrderContext* context) override {
        cout << "错误:订单已发货,不能重复发货" << endl;
    }
    
    void deliver(OrderContext* context) override {
        cout << "订单已送达" << endl;
        context->setState(make_unique<DeliveredState>());
    }
    
    void cancel(OrderContext* context) override {
        cout << "错误:订单已发货,不能取消,请联系客服处理" << endl;
    }
    
    OrderStateType getType() const override {
        return OrderStateType::SHIPPED;
    }
    
    string getDescription() const override {
        return "已发货";
    }
};

// 已送达状态
class DeliveredState : public OrderState {
public:
    void pay(OrderContext* context) override {
        cout << "错误:订单已完成,无需支付" << endl;
    }
    
    void ship(OrderContext* context) override {
        cout << "错误:订单已完成,无需发货" << endl;
    }
    
    void deliver(OrderContext* context) override {
        cout << "错误:订单已完成" << endl;
    }
    
    void cancel(OrderContext* context) override {
        cout << "错误:订单已完成,不能取消" << endl;
    }
    
    OrderStateType getType() const override {
        return OrderStateType::DELIVERED;
    }
    
    string getDescription() const override {
        return "已送达";
    }
};

// 已取消状态
class CancelledState : public OrderState {
public:
    void pay(OrderContext* context) override {
        cout << "错误:订单已取消,无法支付" << endl;
    }
    
    void ship(OrderContext* context) override {
        cout << "错误:订单已取消,无法发货" << endl;
    }
    
    void deliver(OrderContext* context) override {
        cout << "错误:订单已取消,无法确认送达" << endl;
    }
    
    void cancel(OrderContext* context) override {
        cout << "错误:订单已取消" << endl;
    }
    
    OrderStateType getType() const override {
        return OrderStateType::CANCELLED;
    }
    
    string getDescription() const override {
        return "已取消";
    }
};

// 使用示例
int main() {
    cout << "=== 订单状态机示例 ===" << endl;
    
    // 创建订单,初始状态为待支付
    auto order = make_unique<OrderContext>(make_unique<PendingState>());
    
    cout << "\n--- 正常流程 ---" << endl;
    order->pay();      // 支付
    order->ship();     // 发货
    order->deliver();  // 送达
    
    cout << "\n--- 异常流程:未支付直接发货 ---" << endl;
    auto order2 = make_unique<OrderContext>(make_unique<PendingState>());
    order2->ship();    // 尝试直接发货(会被拒绝)
    
    cout << "\n--- 取消流程 ---" << endl;
    auto order3 = make_unique<OrderContext>(make_unique<PendingState>());
    order3->cancel();  // 取消订单
    
    return 0;
}

示例3:状态转换图

支付
取消
发货
取消(退款)
确认送达
退货(特殊流程)
完成
终止
待支付
已支付
已取消
已发货
已送达


第二部分:深层思维思想

六、核心哲学思想

1. "将变化封装在对象内部"的极致体现

状态模式最深刻的思维是:让事物的行为跟随其内在本质(状态)的变化而变化

cpp 复制代码
// 传统思维:外部判断
if (state == "pending") {
    // 处理待支付逻辑
} else if (state == "paid") {
    // 处理已支付逻辑
}

// 状态模式思维:让对象自己知道如何表现
state->handle();  // 不同的状态对象自然有不同的行为

思想精髓:不是"我根据你的状态来决定你该做什么",而是"你根据你自己的状态来决定你该做什么"。

2. "分而治之"思想

将复杂的条件逻辑按照"状态"这个维度进行切分:
复杂的状态相关逻辑
状态1的所有行为
状态2的所有行为
状态3的所有行为
行为A的实现
行为B的实现
行为C的实现

七、思维转变:从"过程式"到"对象式"

对比示例:交通灯系统

传统过程式思维

cpp 复制代码
// 思考角度:我如何控制这个流程?
class TrafficLight {
    int state; // 0=红灯,1=绿灯,2=黄灯
    
    void change() {
        if (state == 0) {
            // 红灯逻辑
            wait(30);
            state = 1;
        } else if (state == 1) {
            // 绿灯逻辑
            wait(25);
            state = 2;
        } else if (state == 2) {
            // 黄灯逻辑
            wait(5);
            state = 0;
        }
    }
};

状态模式思维

cpp 复制代码
// 思考角度:每个状态自己知道如何表现和转换
class RedLight : public LightState {
    void show() override {
        cout << "🔴 红灯,禁止通行" << endl;
    }
    
    void next(LightContext* ctx) override {
        wait(30);
        ctx->setState(new GreenLight()); // 红灯知道下一个是绿灯
    }
};

class GreenLight : public LightState {
    void show() override {
        cout << "🟢 绿灯,请通行" << endl;
    }
    
    void next(LightContext* ctx) override {
        wait(25);
        ctx->setState(new YellowLight()); // 绿灯知道下一个是黄灯
    }
};

思维差异

  • 过程式:外部控制,状态是数据
  • 状态模式:内部自治,状态是行为载体

八、与自然世界的类比理解

1. 水的状态变化

0°C以下
0-100°C
100°C以上
加热
加热
冷却
冷却
水分子H2O
温度决定状态
固态冰
液态水
气态蒸汽

思想映射

  • 水分子 = Context(上下文)
  • 固态/液态/气态 = ConcreteState
  • 温度变化 = 事件触发状态转换
  • 水的行为 = 状态决定(冰能雕刻,水能流动,蒸汽能扩散)

2. 人的情绪状态

cpp 复制代码
// 情绪状态接口
class Emotion {
public:
    virtual void express() = 0;
    virtual void reactToEvent(const string& event) = 0;
};

class Happy : public Emotion {
    void express() override {
        cout << "😊 微笑,积极乐观" << endl;
    }
    
    void reactToEvent(const string& event) override {
        if (event == "批评") {
            cout << "乐观面对,自我改进" << endl;
        } else if (event == "表扬") {
            cout << "更加开心,继续努力" << endl;
        }
    }
};

class Angry : public Emotion {
    void express() override {
        cout << "😠 皱眉,易怒" << endl;
    }
    
    void reactToEvent(const string& event) override {
        if (event == "批评") {
            cout << "愤怒反驳,情绪激动" << endl;
        } else if (event == "表扬") {
            cout << "情绪平复,逐渐冷静" << endl;
        }
    }
};

九、核心思维模式的深度剖析

1. "状态即行为"的思维

传统编程常把状态视为属性 (一个变量),而状态模式把状态视为能力(一组方法)。

cpp 复制代码
// 传统思维:状态是数据
class Document {
    string status;  // "draft", "review", "published"
    
    void submit() {
        if (status == "draft") {
            // 提交逻辑
            status = "review";
        }
    }
};

// 状态模式思维:状态是行为集合
class Document {
    State* currentState;  // 指向行为集合
    
    void submit() {
        currentState->submit(this);  // 委托给状态对象
    }
};

2. "责任转移"思维

将"决策责任"从Context转移到State
状态模式
只负责委托
Context
State接口
State1

自己的决策
State2

自己的决策
State3

自己的决策
传统模式
承担所有决策
Context
if-else迷宫

3. "开闭原则"的完美体现

cpp 复制代码
// 要增加新状态,无需修改现有代码
class NewState : public State {
    void handle() override {
        // 只需添加新类
    }
};

// 传统方式需要修改所有条件判断
void oldWay() {
    if (state == OLD_STATE1) {
        // ...
    } else if (state == OLD_STATE2) {
        // ...
    } else if (state == NEW_STATE) {  // ❌ 修改了现有代码
        // ...
    }
}

十、状态模式 vs 策略模式

很多开发者容易混淆,但它们的思维本质不同

维度 状态模式 策略模式
思维核心 "我是什么,我就怎么做" "我要什么,我就用什么方式"
状态来源 内在的、自发的 外在的、选择的
状态转换 自动转换 手动切换
类比 人的情绪(你无法随意切换) 工具选择(你可以随意选择)
cpp 复制代码
// 状态模式:情绪状态(自动转换)
class Person {
    EmotionState* emotion;
    
    void receiveMessage(const string& msg) {
        emotion->react(msg);  // 情绪自动反应
        // 情绪可能会自动改变
    }
};

// 策略模式:出行策略(主动选择)
class Traveler {
    TransportStrategy* strategy;
    
    void setStrategy(TransportStrategy* s) {
        strategy = s;  // 主动选择策略
    }
    
    void goToWork() {
        strategy->travel();  // 使用选定的策略
    }
};

十一、状态转换的思维模式

1. 集中式转换思维

所有转换逻辑集中在一个地方:

cpp 复制代码
class StateMachine {
    map<pair<State, Event>, State> transitions;
    
    void handleEvent(Event e) {
        State next = transitions[{currentState, e}];
        currentState = next;
    }
};

2. 分布式转换思维

每个状态知道自己的下一个状态:

cpp 复制代码
class DraftState : public State {
    void submit(Context* ctx) override {
        // 草稿状态知道提交后进入审核状态
        ctx->setState(new ReviewState());
    }
};

选择建议

  • 集中式:状态多、转换规则复杂、需要统一管理
  • 分布式:状态少、转换规则清晰、希望保持封装性

十二、思维训练:从状态模式到状态机思维

状态模式培养的是一种状态机思维,这种思维可以应用到更广的领域:

1. 业务流程设计

需求确认
设计完成
开发完成
测试通过
需求分析
设计
开发
测试
上线

2. 用户会话管理

  • 未登录 → 浏览中 → 购物车 → 下单中 → 支付中 → 已完成

3. 设备状态管理

  • 待机 → 运行 → 休眠 → 故障 → 维修中

十三、反模式与思维陷阱

❌ 陷阱1:过度设计

cpp 复制代码
// 只有2个状态的简单场景也使用状态模式
class OnOffState { };  // 过度设计
class Light {
    bool isOn;  // 一个bool就够了
};

❌ 陷阱2:状态类携带大量数据

cpp 复制代码
class StateWithData {
    string data1, data2, data3;  // 不应该存储在状态中
    Context* ctx;  // 数据应该在Context中
};

❌ 陷阱3:状态转换混乱

cpp 复制代码
class StateA {
    void handle(Context* ctx) {
        if (someCondition) {
            ctx->setState(new StateB());
        } else if (otherCondition) {
            ctx->setState(new StateC());
        } else if (complexCondition) {
            ctx->setState(new StateD());  // 转换逻辑过于复杂
        }
    }
};

十四、优缺点分析

优点

  1. 单一职责原则:将不同状态的行为分离到不同的类中
  2. 开闭原则:增加新状态只需添加新的状态类
  3. 消除条件语句:用多态替代复杂的if-else或switch
  4. 状态转换显式化:状态转换逻辑更清晰
  5. 代码可维护性强:状态相关代码集中在具体状态类中

缺点

  1. 类膨胀:每个状态都需要一个具体类
  2. 状态转换分散:状态转换逻辑可能分布在多个状态类中
  3. 上下文与状态耦合:状态类需要持有上下文的引用
  4. 复杂度增加:对于简单状态机可能过度设计

十五、最佳实践建议

  1. 何时使用

    • 对象的行为取决于其状态
    • 有大量的条件判断基于状态
    • 状态数量有限且明确
  2. 实现技巧

    • 考虑使用状态表代替多个状态类
    • 使用单例模式实现无状态的状态对象
    • 结合工厂模式创建状态对象
    • 使用智能指针管理状态对象生命周期
  3. 性能考虑

    • 避免频繁创建状态对象
    • 无状态的状态类可使用单例
    • 状态转换要高效
  4. 与其他模式关系

    • 策略模式:结构相似,但目的不同。状态模式的状态是内在的,策略是外在的
    • 享元模式:可共享状态对象
    • 观察者模式:状态改变时通知观察者

十六、思维总结

状态模式教会我们的不仅是代码组织方式,更是:

  1. 认识世界的角度:事物的行为由其内在状态决定
  2. 分解问题的方法:按状态维度切分复杂逻辑
  3. 代码组织哲学:让数据(状态)拥有行为
  4. 设计思维转变:从"过程控制"到"对象自治"

最高境界:当你看到复杂的if-else或switch时,第一反应不是"如何优化条件判断",而是"这些条件对应的状态是否应该被建模为对象"。

这种思维方式会让你写出更贴近现实世界、更易维护、更易扩展的代码。状态模式不是银弹,但在状态相关的场景下,它是最优雅的解决方案之一。

状态模式特别适合处理复杂的状态转换逻辑,能够显著提高代码的可读性和可维护性。通过将状态相关的行为封装到独立的状态类中,我们不仅消除了冗长的条件语句,还使得每个状态的行为和转换规则变得更加清晰和易于管理。

相关推荐
Sinsa_SI13 小时前
2026算法应用主题赛初赛-小学4-6组(c++)试卷(含答案+详细解析)
java·c++·算法
于小猿Sup13 小时前
ROS Noetic搭建PX4仿真环境
linux·c++·自动驾驶
Zhang~Ling13 小时前
C++继承机制详解上:概念、语法、作用域与转换规则
开发语言·c++
wengqidaifeng13 小时前
C++从菜鸟到强手:2.类和对象(中)—— 拷贝、赋值与运算符重载
开发语言·c++
炘爚14 小时前
智能指针:共享型shared_ptr的底层逻辑
c++·智能指针
不负岁月无痕14 小时前
STL-- C++ vector类 模拟实现
开发语言·c++
丘山望岳14 小时前
C++模板特化:类型与常量的灵活掌控
c语言·开发语言·c++
晚风叙码14 小时前
从0吃透C++入门|第一个程序、命名空间与缺省函数基础
开发语言·c++
j_xxx404_14 小时前
Linux线程:核心机制与优雅的 C++ 封装实践|附源码
linux·运维·服务器·开发语言·c++·人工智能·ai