设计模式(C++)详解——状态模式(State)(1)

<摘要>

状态模式是一种经典的行为型设计模式,它通过将对象不同状态下的行为封装到独立的状态类中,让对象在内部状态变化时自然改变行为,从而避免了冗长的条件判断语句。本文将从背景起源、核心概念、设计意图、实际案例、代码实现等多个维度,全面解析状态模式的原理与应用。我们会通过交通信号灯控制、订单状态管理两个具体案例,展示状态模式如何解决实际开发中的状态管理难题,并提供完整可运行的代码、编译配置及运行说明,帮助读者深入理解并灵活运用这一模式。


<解析>

状态模式(State):让对象的行为随状态优雅变化

一、背景与核心概念:从混乱的条件判断到优雅的状态封装

1.1 模式的起源:当条件判断成为维护的噩梦

想象一下,你正在维护一个电商系统的订单模块。订单会经历"待支付"、"已支付"、"配送中"、"已完成"、"已取消"等多种状态,每种状态下能执行的操作都不同:比如"待支付"状态可以支付或取消,"已支付"状态可以申请退款但不能直接取消,"已完成"状态可以评价但不能退款...

如果用传统方式实现,代码里会充斥着这样的逻辑:

cpp 复制代码
void Order::doAction(Action action) {
    if (m_state == "待支付") {
        if (action == "支付") {
            // 处理支付逻辑
            m_state = "已支付";
        } else if (action == "取消") {
            // 处理取消逻辑
            m_state = "已取消";
        } else {
            // 不支持的操作
        }
    } else if (m_state == "已支付") {
        if (action == "申请退款") {
            // 处理退款逻辑
            m_state = "退款中";
        } else if (action == "发货") {
            // 处理发货逻辑
            m_state = "配送中";
        } else {
            // 不支持的操作
        }
    }
    // ... 更多状态和操作的判断
}

当状态和操作增多时,这段代码会变得无比臃肿,新增加一种状态就需要修改这个巨大的条件判断块,既违反了"开闭原则"(对扩展开放,对修改关闭),又容易引入bug。

20世纪80年代,随着面向对象编程的兴起,开发者开始思考如何更好地处理这类状态依赖的行为。1994年,"四人帮"(Gang of Four, GoF)在《设计模式:可复用面向对象软件的基础》一书中正式提出了状态模式,将不同状态的行为封装到独立的类中,彻底解决了条件判断堆砌的问题。

1.2 核心概念:角色与职责

状态模式的核心是将对象的状态和状态对应的行为分离,通过三个关键角色实现这一目标:

  • 上下文(Context):维护一个指向当前状态的引用,是客户端交互的入口。它会将与状态相关的操作委托给当前状态对象处理。
  • 状态接口(State):定义所有具体状态需要实现的行为接口,通常包含一个或多个与上下文相关的方法。
  • 具体状态(ConcreteState):实现状态接口,包含该状态下的具体行为逻辑。在合适的时机,它会触发状态转换(通过修改上下文的当前状态引用)。

用mermaid类图可以清晰展示它们的关系:
"contains" Context - state: State +Context() +setState(State) +request1() +request2() <<interface>> State +handle1(Context) +handle2(Context) ConcreteStateA +handle1(Context) +handle2(Context) ConcreteStateB +handle1(Context) +handle2(Context)

角色详解

  • Context :比如订单对象、交通信号灯对象。它本身不处理状态相关的逻辑,而是把工作交给当前的State对象。它还提供setState方法允许状态对象切换上下文的状态。
  • State接口 :定义了所有状态都必须实现的行为。比如交通信号灯的light()方法(显示灯光)和nextState()方法(切换到下一个状态)。
  • ConcreteState:比如"红灯状态"、"绿灯状态"。每个具体状态都知道自己能做什么,以及何时切换到其他状态(比如红灯持续30秒后切换到绿灯)。

1.3 状态模式的现状与趋势

如今,状态模式已成为处理复杂状态逻辑的标准方案,广泛应用于:

  • 有限状态机(FSM)实现:如游戏角色状态(站立、行走、攻击、死亡)
  • 工作流系统:如审批流程(部门审批→总经理审批→归档)
  • 设备控制:如打印机状态(空闲→打印中→卡纸→故障)

随着软件系统复杂度的提升,状态模式常与其他模式结合使用:

  • 与单例模式结合:确保每个具体状态只有一个实例(如信号灯的红、黄、绿状态全局唯一)
  • 与建造者模式结合:构建复杂的状态转换流程
  • 与观察者模式结合:状态变化时通知其他对象

在现代框架中,状态模式的思想也被广泛应用。例如,Spring StateMachine提供了基于状态模式的状态管理框架,简化了复杂状态逻辑的开发。

二、设计意图与考量:为什么状态模式是更好的选择

2.1 核心目标:让状态变化驱动行为变化

状态模式的核心意图是:允许一个对象在其内部状态改变时改变它的行为,使得对象看起来似乎修改了它的类

这句话有点绕,我们可以拆解来看:

  • "内部状态改变时改变它的行为":比如订单从"待支付"变为"已支付"后,能执行的操作从"支付/取消"变成了"申请退款/发货"。
  • "看起来似乎修改了它的类":对客户端来说,调用订单的doAction方法时,同一个对象在不同状态下表现出完全不同的行为,就像这个对象突然从"待支付订单类"变成了"已支付订单类"。

这种设计的本质是将状态相关的行为从上下文类中抽离,让上下文的行为由其当前状态动态决定

2.2 设计理念:封装变化,面向接口编程

状态模式遵循两个重要的面向对象设计原则:

  1. 单一职责原则:每个具体状态类只负责一种状态下的行为,职责清晰。
  2. 开闭原则:新增状态时只需添加新的具体状态类,无需修改已有代码。

对比传统的条件判断方式,状态模式的设计理念带来了显著优势:

维度 传统条件判断方式 状态模式
代码复杂度 随状态数量呈指数级增长 线性增长(每个状态对应一个类)
可维护性 差(修改一处可能影响多处) 好(状态行为局部化)
可扩展性 差(需修改已有条件判断) 好(新增状态类即可)
可读性 差(长条件链难以理解) 好(状态行为一目了然)
状态转换管理 分散在条件判断中 集中在具体状态类中

2.3 权衡因素:使用状态模式的利与弊

虽然状态模式优势明显,但也并非没有代价,使用时需要权衡以下因素:

  • 类数量增加:每个状态都需要一个对应的类,可能导致类的数量增多。但这是"以空间换清晰"的合理取舍,相比混乱的条件判断,多几个类带来的维护成本更低。
  • 状态转换的可见性:状态转换逻辑分布在各个具体状态类中,可能不如集中在一个条件判断块中直观。解决方式是通过状态图文档化状态转换关系。
  • 上下文与状态的耦合 :状态对象需要知道上下文才能切换状态(比如ConcreteStateA需要调用context->setState(new ConcreteStateB())),这引入了一定的耦合。但这种耦合是必要的,且可以通过接口抽象降低。

适用场景判断:当一个对象的行为取决于它的状态,且在不同状态下有不同的行为,同时状态转换规则复杂时,状态模式就是最佳选择。反之,如果状态很少、行为简单,用条件判断可能更简洁。

三、实例与应用场景:从理论到实践

案例一:交通信号灯控制系统

场景说明

交通信号灯是状态模式的经典应用场景:信号灯有红、黄、绿三种状态,每种状态有明确的行为(显示对应颜色的灯)和状态转换规则(红→绿→黄→红...循环),且每种状态的持续时间不同(红灯60秒,绿灯50秒,黄灯10秒)。

如果用传统方式实现,代码会充满switch-case判断,新增一种灯(比如特殊的闪烁黄灯)会非常麻烦。用状态模式则可以优雅解决。

实现流程
  1. 定义TrafficLightState接口,包含showLight(显示灯光)和nextState(切换到下一个状态)方法。
  2. 实现三个具体状态类:RedLightStateGreenLightStateYellowLightState,分别实现对应状态的行为。
  3. 定义TrafficLight(上下文)类,维护当前状态,提供run方法启动信号灯循环。
  4. 在具体状态类的nextState方法中,根据规则切换TrafficLight的当前状态(如红灯结束后切换到绿灯)。
代码实现

traffic_light.h

cpp 复制代码
#ifndef TRAFFIC_LIGHT_H
#define TRAFFIC_LIGHT_H

#include <iostream>
#include <chrono>
#include <thread>

/**
 * @brief 交通信号灯状态接口
 * 
 * 定义所有信号灯状态必须实现的行为:显示灯光和切换到下一个状态
 */
class TrafficLightState {
public:
    /**
     * @brief 纯虚析构函数,确保子类正确析构
     */
    virtual ~TrafficLightState() = default;

    /**
     * @brief 显示当前状态的灯光
     * 
     * 不同状态(红、黄、绿)会实现不同的显示逻辑
     */
    virtual void showLight() = 0;

    /**
     * @brief 切换到下一个状态
     * 
     * @param context 交通信号灯上下文对象,用于设置新的状态
     */
    virtual void nextState(class TrafficLight* context) = 0;

    /**
     * @brief 获取当前状态的持续时间(秒)
     * 
     * @return int 持续时间(秒)
     */
    virtual int getDuration() = 0;
};

/**
 * @brief 交通信号灯上下文类
 * 
 * 维护当前状态,提供状态切换的入口,控制信号灯的运行
 */
class TrafficLight {
private:
    TrafficLightState* m_currentState; ///< 当前状态

public:
    /**
     * @brief 构造函数,初始化信号灯状态为红灯
     */
    TrafficLight();

    /**
     * @brief 析构函数,释放当前状态对象
     */
    ~TrafficLight();

    /**
     * @brief 设置信号灯的当前状态
     * 
     * @in:
     *   - state: 新的状态对象指针
     * 
     * @out:
     *   - m_currentState: 更新为新的状态
     */
    void setState(TrafficLightState* state);

    /**
     * @brief 显示当前状态的灯光
     * 
     * 委托给当前状态对象处理
     */
    void showLight();

    /**
     * @brief 切换到下一个状态
     * 
     * 委托给当前状态对象处理
     */
    void nextState();

    /**
     * @brief 获取当前状态的持续时间
     * 
     * @return int 持续时间(秒)
     */
    int getCurrentDuration();

    /**
     * @brief 启动信号灯运行
     * 
     * 循环显示当前灯光,等待对应时长后切换到下一个状态
     * 按Ctrl+C可终止程序
     */
    void run();
};

/**
 * @brief 红灯状态类
 * 
 * 实现红灯的显示逻辑和状态转换(红灯→绿灯)
 */
class RedLightState : public TrafficLightState {
public:
    /**
     * @brief 显示红灯
     * 
     * 输出红灯提示信息
     */
    void showLight() override;

    /**
     * @brief 切换到绿灯状态
     * 
     * @param context 交通信号灯上下文对象
     */
    void nextState(TrafficLight* context) override;

    /**
     * @brief 获取红灯持续时间(60秒)
     * 
     * @return int 60
     */
    int getDuration() override;
};

/**
 * @brief 绿灯状态类
 * 
 * 实现绿灯的显示逻辑和状态转换(绿灯→黄灯)
 */
class GreenLightState : public TrafficLightState {
public:
    /**
     * @brief 显示绿灯
     * 
     * 输出绿灯提示信息
     */
    void showLight() override;

    /**
     * @brief 切换到黄灯状态
     * 
     * @param context 交通信号灯上下文对象
     */
    void nextState(TrafficLight* context) override;

    /**
     * @brief 获取绿灯持续时间(50秒)
     * 
     * @return int 50
     */
    int getDuration() override;
};

/**
 * @brief 黄灯状态类
 * 
 * 实现黄灯的显示逻辑和状态转换(黄灯→红灯)
 */
class YellowLightState : public TrafficLightState {
public:
    /**
     * @brief 显示黄灯
     * 
     * 输出黄灯提示信息
     */
    void showLight() override;

    /**
     * @brief 切换到红灯状态
     * 
     * @param context 交通信号灯上下文对象
     */
    void nextState(TrafficLight* context) override;

    /**
     * @brief 获取黄灯持续时间(10秒)
     * 
     * @return int 10
     */
    int getDuration() override;
};

#endif // TRAFFIC_LIGHT_H

traffic_light.cpp

cpp 复制代码
#include "traffic_light.h"

// TrafficLight类实现
TrafficLight::TrafficLight() {
    // 初始状态为红灯
    m_currentState = new RedLightState();
}

TrafficLight::~TrafficLight() {
    delete m_currentState;
}

void TrafficLight::setState(TrafficLightState* state) {
    if (m_currentState != nullptr) {
        delete m_currentState;
    }
    m_currentState = state;
}

void TrafficLight::showLight() {
    m_currentState->showLight();
}

void TrafficLight::nextState() {
    m_currentState->nextState(this);
}

int TrafficLight::getCurrentDuration() {
    return m_currentState->getDuration();
}

void TrafficLight::run() {
    std::cout << "交通信号灯启动,按Ctrl+C退出..." << std::endl;
    while (true) {
        // 显示当前灯光
        showLight();
        // 获取当前状态持续时间
        int duration = getCurrentDuration();
        // 等待对应时长(单位:毫秒)
        std::this_thread::sleep_for(std::chrono::seconds(duration));
        // 切换到下一个状态
        nextState();
    }
}

// RedLightState类实现
void RedLightState::showLight() {
    std::cout << "\033[1;31m[红灯亮]\033[0m 车辆禁止通行,行人可以通行" << std::endl;
}

void RedLightState::nextState(TrafficLight* context) {
    context->setState(new GreenLightState());
}

int RedLightState::getDuration() {
    return 60; // 红灯持续60秒
}

// GreenLightState类实现
void GreenLightState::showLight() {
    std::cout << "\033[1;32m[绿灯亮]\033[0m 车辆可以通行,行人禁止通行" << std::endl;
}

void GreenLightState::nextState(TrafficLight* context) {
    context->setState(new YellowLightState());
}

int GreenLightState::getDuration() {
    return 50; // 绿灯持续50秒
}

// YellowLightState类实现
void YellowLightState::showLight() {
    std::cout << "\033[1;33m[黄灯亮]\033[0m 车辆准备停车,行人禁止通行" << std::endl;
}

void YellowLightState::nextState(TrafficLight* context) {
    context->setState(new RedLightState());
}

int YellowLightState::getDuration() {
    return 10; // 黄灯持续10秒
}

main.cpp

cpp 复制代码
#include "traffic_light.h"

/**
 * @brief 主函数,启动交通信号灯系统
 * 
 * @return int 程序退出码(0表示正常退出)
 */
int main() {
    TrafficLight trafficLight;
    trafficLight.run();
    return 0;
}
核心逻辑流程图

用mermaid流程图展示信号灯的状态转换流程:
启动信号灯 初始化状态为红灯 显示红灯(60秒) 等待60秒 切换到绿灯状态 显示绿灯(50秒) 等待50秒 切换到黄灯状态 显示黄灯(10秒) 等待10秒 切换到红灯状态

Makefile
makefile 复制代码
# 编译器设置
CXX = g++
CXXFLAGS = -std=c++11 -Wall -Wextra -O2

# 目标文件和可执行文件
TARGET = traffic_light_app
OBJS = main.o traffic_light.o

# 默认目标
all: $(TARGET)

# 链接
$(TARGET): $(OBJS)
	$(CXX) $(CXXFLAGS) -o $@ $(OBJS)

# 编译
main.o: main.cpp traffic_light.h
	$(CXX) $(CXXFLAGS) -c -o $@ main.cpp

traffic_light.o: traffic_light.cpp traffic_light.h
	$(CXX) $(CXXFLAGS) -c -o $@ traffic_light.cpp

# 清理
clean:
	rm -f $(OBJS) $(TARGET)

# 伪目标
.PHONY: all clean
操作说明
  1. 编译方法

    • 依赖:需要支持C++11的编译器(如g++ 4.8及以上版本)
    • 编译命令:make clean && make
    • 执行后会生成可执行文件traffic_light_app
  2. 运行方式

    • 运行命令:./traffic_light_app
    • 程序会持续运行,循环显示红、绿、黄灯状态
  3. 结果解读

    • 正常输出:

      复制代码
      交通信号灯启动,按Ctrl+C退出...
      [红灯亮] 车辆禁止通行,行人可以通行
      (等待60秒后)
      [绿灯亮] 车辆可以通行,行人禁止通行
      (等待50秒后)
      [黄灯亮] 车辆准备停车,行人禁止通行
      (等待10秒后)
      [红灯亮] 车辆禁止通行,行人可以通行
      ...(循环)
    • 异常提示:无特殊异常,按Ctrl+C可终止程序

案例二:电商订单状态管理系统

场景说明

电商订单的状态管理是状态模式的另一个典型应用。一个订单通常会经历以下状态:

  • 待支付(OrderCreated):用户下单后未支付的状态,可执行"支付"、"取消订单"操作
  • 已支付(Paid):用户完成支付,可执行"申请退款"、"商家发货"操作
  • 配送中(Shipped):商家已发货,可执行"确认收货"操作
  • 已完成(Completed):用户确认收货,可执行"评价"操作
  • 已取消(Cancelled):订单被取消,无有效操作
  • 退款中(Refunding):用户申请退款后,可执行"退款完成"操作

每种状态下的操作不同,且操作会触发状态转换(如"支付"操作将订单从"待支付"转为"已支付")。

实现流程
  1. 定义OrderState接口,包含所有可能的订单操作(支付、取消、发货等)。
  2. 为每个订单状态实现具体状态类(如OrderCreatedStatePaidState等),在不支持的操作中抛出异常。
  3. 定义Order(上下文)类,包含订单基本信息(订单号、金额等)和当前状态,提供操作入口。
  4. 在具体状态类的操作方法中,执行业务逻辑并切换订单状态(如OrderCreatedState::pay方法将订单状态改为PaidState)。
代码实现

order_state.h

cpp 复制代码
#ifndef ORDER_STATE_H
#define ORDER_STATE_H

#include <string>
#include <stdexcept>
#include <iostream>

// 前向声明
class Order;

/**
 * @brief 订单状态接口
 * 
 * 定义所有订单状态可能涉及的操作
 */
class OrderState {
public:
    /**
     * @brief 纯虚析构函数
     */
    virtual ~OrderState() = default;

    /**
     * @brief 获取当前状态名称
     * 
     * @return std::string 状态名称(如"待支付")
     */
    virtual std::string getStateName() const = 0;

    /**
     * @brief 支付订单
     * 
     * @param order 订单对象
     * @throw std::invalid_argument 如果当前状态不支持支付操作
     */
    virtual void pay(Order* order);

    /**
     * @brief 取消订单
     * 
     * @param order 订单对象
     * @throw std::invalid_argument 如果当前状态不支持取消操作
     */
    virtual void cancel(Order* order);

    /**
     * @brief 商家发货
     * 
     * @param order 订单对象
     * @throw std::invalid_argument 如果当前状态不支持发货操作
     */
    virtual void ship(Order* order);

    /**
     * @brief 用户确认收货
     * 
     * @param order 订单对象
     * @throw std::invalid_argument 如果当前状态不支持确认收货操作
     */
    virtual void confirmReceipt(Order* order);

    /**
     * @brief 申请退款
     * 
     * @param order 订单对象
     * @throw std::invalid_argument 如果当前状态不支持申请退款操作
     */
    virtual void applyRefund(Order* order);

    /**
     * @brief 完成退款
     * 
     * @param order 订单对象
     * @throw std::invalid_argument 如果当前状态不支持完成退款操作
     */
    virtual void completeRefund(Order* order);

    /**
     * @brief 评价订单
     * 
     * @param order 订单对象
     * @param comment 评价内容
     * @throw std::invalid_argument 如果当前状态不支持评价操作
     */
    virtual void comment(Order* order, const std::string& comment);
};

/**
 * @brief 订单类(上下文)
 * 
 * 维护订单信息和当前状态,提供操作入口
 */
class Order {
private:
    std::string m_orderId;      ///< 订单号
    double m_amount;            ///< 订单金额
    OrderState* m_currentState; ///< 当前状态
    std::string m_comment;      ///< 订单评价

public:
    /**
     * @brief 构造函数
     * 
     * @param orderId 订单号
     * @param amount 订单金额
     */
    Order(const std::string& orderId, double amount);

    /**
     * @brief 析构函数
     */
    ~Order();

    /**
     * @brief 设置订单状态
     * 
     * @in:
     *   - state: 新的状态对象
     * 
     * @out:
     *   - m_currentState: 更新为新状态
     */
    void setState(OrderState* state);

    /**
     * @brief 获取当前订单状态名称
     * 
     * @return std::string 状态名称
     */
    std::string getCurrentStateName() const;

    /**
     * @brief 获取订单号
     * 
     * @return std::string 订单号
     */
    std::string getOrderId() const;

    /**
     * @brief 获取订单金额
     * 
     * @return double 订单金额
     */
    double getAmount() const;

    /**
     * @brief 设置订单评价
     * 
     * @param comment 评价内容
     */
    void setComment(const std::string& comment);

    /**
     * @brief 获取订单评价
     * 
     * @return std::string 评价内容
     */
    std::string getComment() const;

    // 以下为订单操作的入口方法,委托给当前状态处理

    /**
     * @brief 支付订单
     */
    void pay();

    /**
     * @brief 取消订单
     */
    void cancel();

    /**
     * @brief 商家发货
     */
    void ship();

    /**
     * @brief 用户确认收货
     */
    void confirmReceipt();

    /**
     * @brief 申请退款
     */
    void applyRefund();

    /**
     * @brief 完成退款
     */
    void completeRefund();

    /**
     * @brief 评价订单
     * 
     * @param comment 评价内容
     */
    void comment(const std::string& comment);
};

/**
 * @brief 待支付状态
 */
class OrderCreatedState : public OrderState {
public:
    std::string getStateName() const override;
    void pay(Order* order) override;
    void cancel(Order* order) override;
};

/**
 * @brief 已支付状态
 */
class PaidState : public OrderState {
public:
    std::string getStateName() const override;
    void ship(Order* order) override;
    void applyRefund(Order* order) override;
};

/**
 * @brief 配送中状态
 */
class ShippedState : public OrderState {
public:
    std::string getStateName() const override;
    void confirmReceipt(Order* order) override;
};

/**
 * @brief 已完成状态
 */
class CompletedState : public OrderState {
public:
    std::string getStateName() const override;
    void comment(Order* order, const std::string& comment) override;
};

/**
 * @brief 已取消状态
 */
class CancelledState : public OrderState {
public:
    std::string getStateName() const override;
};

/**
 * @brief 退款中状态
 */
class RefundingState : public OrderState {
public:
    std::string getStateName() const override;
    void completeRefund(Order* order) override;
};

#endif // ORDER_STATE_H

order_state.cpp

cpp 复制代码
#include "order_state.h"

// OrderState接口默认实现(不支持的操作抛出异常)
void OrderState::pay(Order* order) {
    throw std::invalid_argument("当前状态(" + getStateName() + ")不支持支付操作");
}

void OrderState::cancel(Order* order) {
    throw std::invalid_argument("当前状态(" + getStateName() + ")不支持取消操作");
}

void OrderState::ship(Order* order) {
    throw std::invalid_argument("当前状态(" + getStateName() + ")不支持发货操作");
}

void OrderState::confirmReceipt(Order* order) {
    throw std::invalid_argument("当前状态(" + getStateName() + ")不支持确认收货操作");
}

void OrderState::applyRefund(Order* order) {
    throw std::invalid_argument("当前状态(" + getStateName() + ")不支持申请退款操作");
}

void OrderState::completeRefund(Order* order) {
    throw std::invalid_argument("当前状态(" + getStateName() + ")不支持完成退款操作");
}

void OrderState::comment(Order* order, const std::string& comment) {
    throw std::invalid_argument("当前状态(" + getStateName() + ")不支持评价操作");
}

// Order类实现
Order::Order(const std::string& orderId, double amount) 
    : m_orderId(orderId), m_amount(amount), m_currentState(new OrderCreatedState()), m_comment("") {}

Order::~Order() {
    delete m_currentState;
}

void Order::setState(OrderState* state) {
    if (m_currentState != nullptr) {
        delete m_currentState;
    }
    m_currentState = state;
    std::cout << "订单[" << m_orderId << "]状态变更为:" << m_currentState->getStateName() << std::endl;
}

std::string Order::getCurrentStateName() const {
    return m_currentState->getStateName();
}

std::string Order::getOrderId() const {
    return m_orderId;
}

double Order::getAmount() const {
    return m_amount;
}

void Order::setComment(const std::string& comment) {
    m_comment = comment;
}

std::string Order::getComment() const {
    return m_comment;
}

void Order::pay() {
    m_currentState->pay(this);
}

void Order::cancel() {
    m_currentState->cancel(this);
}

void Order::ship() {
    m_currentState->ship(this);
}

void Order::confirmReceipt() {
    m_currentState->confirmReceipt(this);
}

void Order::applyRefund() {
    m_currentState->applyRefund(this);
}

void Order::completeRefund() {
    m_currentState->completeRefund(this);
}

void Order::comment(const std::string& comment) {
    m_currentState->comment(this, comment);
}

// OrderCreatedState(待支付)实现
std::string OrderCreatedState::getStateName() const {
    return "待支付";
}

void OrderCreatedState::pay(Order* order) {
    std::cout << "订单[" << order->getOrderId() << "]支付成功,金额:" << order->getAmount() << "元" << std::endl;
    order->setState(new PaidState());
}

void OrderCreatedState::cancel(Order* order) {
    std::cout << "订单[" << order->getOrderId() << "]已取消" << std::endl;
    order->setState(new CancelledState());
}

// PaidState(已支付)实现
std::string PaidState::getStateName() const {
    return "已支付";
}

void PaidState::ship(Order* order) {
    std::cout << "订单[" << order->getOrderId() << "]已发货" << std::endl;
    order->setState(new ShippedState());
}

void PaidState::applyRefund(Order* order) {
    std::cout << "订单[" << order->getOrderId() << "]已申请退款,金额:" << order->getAmount() << "元" << std::endl;
    order->setState(new RefundingState());
}

// ShippedState(配送中)实现
std::string ShippedState::getStateName() const {
    return "配送中";
}

void ShippedState::confirmReceipt(Order* order) {
    std::cout << "订单[" << order->getOrderId() << "]已确认收货" << std::endl;
    order->setState(new CompletedState());
}

// CompletedState(已完成)实现
std::string CompletedState::getStateName() const {
    return "已完成";
}

void CompletedState::comment(Order* order, const std::string& comment) {
    std::cout << "订单[" << order->getOrderId() << "]评价成功:" << comment << std::endl;
    order->setComment(comment);
}

// CancelledState(已取消)实现
std::string CancelledState::getStateName() const {
    return "已取消";
}

// RefundingState(退款中)实现
std::string RefundingState::getStateName() const {
    return "退款中";
}

void RefundingState::completeRefund(Order* order) {
    std::cout << "订单[" << order->getOrderId() << "]退款完成,金额:" << order->getAmount() << "元" << std::endl;
    order->setState(new CancelledState());
}

main.cpp

cpp 复制代码
#include "order_state.h"
#include <iostream>

/**
 * @brief 展示订单操作示例
 * 
 * 模拟一个正常完成的订单流程和一个申请退款的订单流程
 * 
 * @return int 程序退出码(0表示正常退出)
 */
int main() {
    // 示例1:正常完成的订单流程
    std::cout << "===== 正常订单流程 =====" << std::endl;
    Order normalOrder("ORD20251003001", 99.9);
    try {
        normalOrder.pay();         // 待支付→已支付
        normalOrder.ship();        // 已支付→配送中
        normalOrder.confirmReceipt(); // 配送中→已完成
        normalOrder.comment("商品质量很好,推荐购买!"); // 已完成状态评价
    } catch (const std::exception& e) {
        std::cout << "操作失败:" << e.what() << std::endl;
    }

    // 示例2:申请退款的订单流程
    std::cout << "\n===== 退款订单流程 =====" << std::endl;
    Order refundOrder("ORD20251003002", 199.5);
    try {
        refundOrder.pay();         // 待支付→已支付
        refundOrder.applyRefund(); // 已支付→退款中
        refundOrder.completeRefund(); // 退款中→已取消
        // 尝试对已取消的订单进行发货(应该失败)
        refundOrder.ship();
    } catch (const std::exception& e) {
        std::cout << "操作失败:" << e.what() << std::endl;
    }

    return 0;
}
核心逻辑时序图

用mermaid时序图展示正常订单的状态转换过程:
Client 订单(ORD20251003001) 待支付状态 已支付状态 配送中状态 已完成状态 初始状态为待支付 pay() pay(Order) 切换到已支付状态 状态更新完成 ship() ship(Order) 切换到配送中状态 状态更新完成 confirmReceipt() confirmReceipt(Order) 切换到已完成状态 状态更新完成 comment("好评") comment(Order, "好评") 保存评价内容 Client 订单(ORD20251003001) 待支付状态 已支付状态 配送中状态 已完成状态

Makefile
makefile 复制代码
# 编译器设置
CXX = g++
CXXFLAGS = -std=c++11 -Wall -Wextra -O2

# 目标文件和可执行文件
TARGET = order_state_app
OBJS = main.o order_state.o

# 默认目标
all: $(TARGET)

# 链接
$(TARGET): $(OBJS)
	$(CXX) $(CXXFLAGS) -o $@ $(OBJS)

# 编译
main.o: main.cpp order_state.h
	$(CXX) $(CXXFLAGS) -c -o $@ main.cpp

order_state.o: order_state.cpp order_state.h
	$(CXX) $(CXXFLAGS) -c -o $@ order_state.cpp

# 清理
clean:
	rm -f $(OBJS) $(TARGET)

# 伪目标
.PHONY: all clean
操作说明
  1. 编译方法

    • 依赖:支持C++11的编译器(如g++ 4.8及以上)
    • 编译命令:make clean && make
    • 生成可执行文件order_state_app
  2. 运行方式

    • 运行命令:./order_state_app
    • 程序无需参数,直接运行即可展示两个订单流程
  3. 结果解读

    • 正常输出:

      复制代码
      ===== 正常订单流程 =====
      订单[ORD20251003001]状态变更为:待支付
      订单[ORD20251003001]支付成功,金额:99.9元
      订单[ORD20251003001]状态变更为:已支付
      订单[ORD20251003001]已发货
      订单[ORD20251003001]状态变更为:配送中
      订单[ORD20251003001]已确认收货
      订单[ORD20251003001]状态变更为:已完成
      订单[ORD20251003001]评价成功:商品质量很好,推荐购买!
      
      ===== 退款订单流程 =====
      订单[ORD20251003002]状态变更为:待支付
      订单[ORD20251003002]支付成功,金额:199.5元
      订单[ORD20251003002]状态变更为:已支付
      订单[ORD20251003002]已申请退款,金额:199.5元
      订单[ORD20251003002]状态变更为:退款中
      订单[ORD20251003002]退款完成,金额:199.5元
      订单[ORD20251003002]状态变更为:已取消
      操作失败:当前状态(已取消)不支持发货操作
    • 异常提示:当对订单执行当前状态不支持的操作时(如对已取消订单执行发货),会抛出异常并提示具体原因

四、状态模式的扩展与思考

4.1 与其他模式的对比

状态模式 vs 策略模式

状态模式和策略模式的类图结构非常相似(都有一个上下文类和多个实现接口的具体类),但它们的意图完全不同:

  • 状态模式:关注对象状态的变化及状态对行为的影响,状态之间通常存在依赖关系(如红灯之后必须是绿灯),状态转换由状态对象或上下文控制。
  • 策略模式:关注算法的替换,策略之间相互独立,客户端可以自由选择策略,策略的选择由客户端决定。

简单说:状态模式是"我自己根据状态变",策略模式是"你让我用哪个我就用哪个"。

状态模式 vs 状态机

状态模式是实现有限状态机(FSM)的一种方式,但状态机更偏向于一种数学模型,而状态模式是具体的代码实现方法。除了状态模式,还可以用表驱动法(如状态-事件表)实现状态机,但状态模式的面向对象特性更适合复杂状态逻辑。

4.2 状态模式的高级应用

共享状态实例

当多个上下文对象可以共享同一个状态时(如所有订单的"已取消"状态行为相同),可以使用单例模式确保每个具体状态只有一个实例,节省内存。

示例:将CancelledState改为单例:

cpp 复制代码
class CancelledState : public OrderState {
private:
    // 私有构造函数,防止外部实例化
    CancelledState() = default;

public:
    // 禁止拷贝和赋值
    CancelledState(const CancelledState&) = delete;
    CancelledState& operator=(const CancelledState&) = delete;

    // 全局唯一实例
    static CancelledState* getInstance() {
        static CancelledState instance;
        return &instance;
    }

    std::string getStateName() const override {
        return "已取消";
    }
};

// 使用时:
order->setState(CancelledState::getInstance());
状态持久化

在实际系统中,状态需要持久化存储(如订单状态保存在数据库)。可以在状态转换时同步更新数据库,或在上下文初始化时从数据库加载状态。

示例:Order类加载状态:

cpp 复制代码
Order::Order(const std::string& orderId) {
    m_orderId = orderId;
    // 从数据库查询状态
    std::string stateName = db.queryState(orderId);
    // 根据状态名称创建对应的状态对象
    if (stateName == "待支付") {
        m_currentState = new OrderCreatedState();
    } else if (stateName == "已支付") {
        m_currentState = new PaidState();
    }
    // ... 其他状态
}

4.3 状态模式的局限性与应对

  • 类爆炸:状态过多时,类的数量会急剧增加。可以通过合并相似状态、使用组合状态等方式缓解。
  • 状态转换逻辑分散:状态转换规则分布在各个状态类中,不便于全局把握。可以通过状态转换图文档化,或引入"状态管理器"统一管理转换规则。
  • 上下文与状态的耦合:状态需要知道上下文才能切换状态。可以通过引入中介者模式,让状态通过中介者与上下文交互,降低直接耦合。

五、总结:让状态管理变得优雅

状态模式通过将对象的状态和行为分离,彻底解决了传统条件判断方式带来的代码臃肿、维护困难等问题。它遵循面向对象的设计原则,让系统更具灵活性和可扩展性。

无论是交通信号灯、订单管理,还是游戏角色状态、设备控制,只要涉及复杂的状态转换和状态依赖行为,状态模式都是值得考虑的优秀解决方案。

使用状态模式的核心收益在于:

  1. 代码清晰:每个状态的行为集中在对应的类中,一目了然。
  2. 易于维护:修改一个状态的行为只需修改对应的类,不影响其他状态。
  3. 便于扩展:新增状态只需添加新的状态类,符合开闭原则。
  4. 状态转换可控:状态转换规则由状态类自主控制,逻辑清晰。

当然,状态模式也不是银弹,在状态简单、行为单一的场景下,过度使用反而会增加系统复杂度。作为开发者,我们需要根据实际场景权衡利弊,选择最合适的实现方式。

希望通过本文的讲解,你能对状态模式有深入的理解,并能在实际开发中灵活运用,让你的代码更加优雅、健壮!

相关推荐
haoly19892 小时前
数据结构与算法篇--语义智能指针设计模式
数据结构·设计模式
千里马-horse3 小时前
Async++ 源码分析3---cancel.h
开发语言·c++·async++·cancel
渡我白衣4 小时前
C++ :std::bind 还能用吗?它和 Lambda 有什么区别?
开发语言·c++·c++20
胖咕噜的稞达鸭4 小时前
算法入门:专题攻克主题一---双指针(1)移动零 复写零
c语言·开发语言·c++·算法
一只小bit4 小时前
CMake 入门实战手册:从理解原理开始,打造高效 C/C++ 开发流程
c语言·开发语言·c++·cmake
青草地溪水旁5 小时前
设计模式(C++)详解——策略模式(1)
c++·设计模式·策略模式
o0向阳而生0o5 小时前
105、23种设计模式之策略模式(14/23)
设计模式·策略模式
余衫马5 小时前
llama.cpp:本地大模型推理的高性能 C++ 框架
c++·人工智能·llm·llama·大模型部署
胖咕噜的稞达鸭6 小时前
算法入门:专题攻克主题一---双指针(2)快乐数 呈最多水的容器
开发语言·数据结构·c++·算法