首页 自动驾驶

C++ 设计模式实战:用状态模式优雅应对复杂状态流转

分类:自动驾驶
字数: (9250)
阅读: (5411)
内容摘要:C++ 设计模式实战:用状态模式优雅应对复杂状态流转,

在复杂的软件系统中,对象的状态变化往往会引发一系列不同的行为。如果我们直接在对象内部使用大量的 if-elseswitch-case 语句来处理这些状态,代码会变得难以维护和扩展。这时,状态模式就派上了用场。它允许对象在内部状态改变时改变它的行为,使其看起来好像修改了它的类。

问题场景重现:订单状态流转

想象一下一个电商系统的订单状态流转:待支付、已支付、待发货、已发货、已完成、已取消。不同的状态下,允许的操作是不同的。例如,只有在待支付状态下才能进行支付操作,只有在已支付状态下才能进行发货操作。如果我们直接在 Order 类中处理这些逻辑,代码会非常臃肿。

C++ 设计模式实战:用状态模式优雅应对复杂状态流转
class Order {
public:
  enum class State {
    PENDING_PAYMENT,
    PAID,
    PENDING_SHIPMENT,
    SHIPPED,
    COMPLETED,
    CANCELLED
  };

private:
  State state;

public:
  void pay() {
    if (state == State::PENDING_PAYMENT) {
      // 执行支付逻辑
      state = State::PAID;
      std::cout << "Payment successful!" << std::endl;
    } else {
      std::cout << "Cannot pay in current state." << std::endl;
    }
  }

  void ship() {
    if (state == State::PAID) {
      // 执行发货逻辑
      state = State::PENDING_SHIPMENT;
      std::cout << "Order shipped!" << std::endl;
    } else {
      std::cout << "Cannot ship in current state." << std::endl;
    }
  }

  // ... 其他状态和操作
};

可以看到,随着状态的增加,Order 类会变得越来越复杂。这正是状态模式要解决的问题。

C++ 设计模式实战:用状态模式优雅应对复杂状态流转

底层原理深度剖析:状态模式的结构

状态模式的核心思想是将状态相关的行为封装到独立的状态类中,并通过委托的方式让上下文对象(例如上面的 Order 类)来调用这些状态类的行为。

C++ 设计模式实战:用状态模式优雅应对复杂状态流转

状态模式主要包含以下几个角色:

C++ 设计模式实战:用状态模式优雅应对复杂状态流转
  • Context(上下文): 包含一个指向当前状态对象的引用,并将客户端的请求委托给当前状态对象处理。
  • State(抽象状态): 定义一个接口,用于封装与上下文对象的一个特定状态相关的行为。
  • ConcreteState(具体状态): 实现 State 接口,封装与上下文对象的一个具体状态相关的行为。

代码实现:状态模式重构订单系统

#include <iostream>
#include <string>

// 抽象状态类
class State {
public:
    virtual void pay() = 0;
    virtual void ship() = 0;
    virtual void complete() = 0;
    virtual void cancel() = 0;
    virtual std::string getStateName() = 0; // 获取状态名称
    virtual ~State() {}
};

// 具体状态类 - 待支付
class PendingPaymentState : public State {
public:
    void pay() override {
        std::cout << "Payment successful! Order transitioning to Paid state.\n";
        // 这里应该返回一个新的状态对象,比如PaidState的实例
    }
    void ship() override { std::cout << "Cannot ship: Order is pending payment.\n"; }
    void complete() override { std::cout << "Cannot complete: Order is pending payment.\n"; }
    void cancel() override { std::cout << "Order cancelled.\n"; }
    std::string getStateName() override { return "Pending Payment"; }
};

// 具体状态类 - 已支付
class PaidState : public State {
public:
    void pay() override { std::cout << "Order already paid.\n"; }
    void ship() override {
        std::cout << "Order shipped! Transitioning to Shipped state.\n";
        // 返回 ShippedState
    }
    void complete() override { std::cout << "Cannot complete: Order is awaiting shipment.\n"; }
    void cancel() override { std::cout << "Order cannot be cancelled after payment.\n"; }
    std::string getStateName() override { return "Paid"; }
};

// 具体状态类 - 待发货
class PendingShipmentState : public State {
public:
    void pay() override { std::cout << "Order already paid.\n"; }
    void ship() override { std::cout << "Order already shipped.\n"; }
    void complete() override {
        std::cout << "Order completed!\n";
        // 返回 CompletedState
    }
    void cancel() override { std::cout << "Order cannot be cancelled after shipment.\n"; }
    std::string getStateName() override { return "Pending Shipment"; }
};

// 上下文类 - 订单
class Order {
private:
    State* currentState;  // 当前状态

public:
    Order() : currentState(new PendingPaymentState()) {}
    ~Order() { delete currentState; }

    void setState(State* newState) {
        delete currentState; // 防止内存泄漏
        currentState = newState;
    }

    void pay() { currentState->pay(); }
    void ship() { currentState->ship(); }
    void complete() { currentState->complete(); }
    void cancel() { currentState->cancel(); }
    std::string getCurrentStateName() { return currentState->getStateName(); }
};

int main() {
    Order order;
    std::cout << "Current state: " << order.getCurrentStateName() << std::endl;  // Pending Payment
    order.pay(); // Payment successful! Order transitioning to Paid state.

    // 假设支付成功后,Order的状态需要更新,这里简化处理,实际应该在pay()方法内返回新的State
    order.setState(new PaidState());
    std::cout << "Current state: " << order.getCurrentStateName() << std::endl;  // Paid

    order.ship(); // Order shipped! Transitioning to Shipped state.

    // 假设发货成功后,Order的状态需要更新
    order.setState(new PendingShipmentState());
    std::cout << "Current state: " << order.getCurrentStateName() << std::endl;  // Pending Shipment

    order.complete(); // Order completed!

    return 0;
}

实战避坑经验总结

  1. 状态切换的责任归属: 状态切换可以由 Context 对象或 ConcreteState 对象负责。如果状态切换逻辑简单,可以放在 Context 中;如果状态切换逻辑复杂,最好放在 ConcreteState 中,避免 Context 变得臃肿。
  2. 状态对象的管理: 多个 Context 对象可能共享同一个状态对象,这时可以使用单例模式来管理状态对象,避免创建过多的对象。当然,也要注意线程安全问题,尤其是在高并发场景下,例如使用 Nginx 作为反向代理服务器,处理大量并发连接时,如果状态对象是共享的,就需要加锁保护。
  3. 避免过度设计: 状态模式虽然强大,但也增加了代码的复杂性。只有在状态数量较多,且状态转换逻辑复杂时,才考虑使用状态模式。否则,简单的 if-elseswitch-case 语句可能更合适。
  4. 配合其他设计模式: 状态模式常常和其他设计模式一起使用,例如策略模式、工厂模式等,以实现更灵活的设计。

状态模式与 Nginx 的关联思考

虽然 Nginx 自身没有直接使用状态模式,但 Nginx 处理请求的过程可以类比为状态机的状态转换。例如,接收到客户端请求、建立连接、处理请求头、处理请求体、发送响应等都可以看作是不同的状态。Nginx 通过事件驱动机制来处理这些状态的转换,高效地处理并发请求。 了解状态模式,可以帮助我们更好地理解 Nginx 的内部运作机制,例如 Nginx 的模块开发,就可以通过定义不同的模块来处理不同状态下的请求。

通过 C++ 实现的状态模式能够很好地解决对象状态转换复杂的问题,提高代码的可维护性和可扩展性。在实际项目中,需要结合具体的业务场景,灵活运用各种设计模式,才能构建出高质量的软件系统。

C++ 设计模式实战:用状态模式优雅应对复杂状态流转

转载请注明出处: 代码一只喵

本文的链接地址: http://m.acea5.store/blog/282198.SHTML

本文最后 发布于2026-04-14 06:30:33,已经过了13天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 广东肠粉 3 天前
    状态模式可以避免大量的 if-else 语句,提高代码的可读性和可维护性。不过感觉在状态比较少的情况下,用 if-else 更简单直接呢。