当前位置: 首页 > news >正文

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

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


<解析>

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

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

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

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

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

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

#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

#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

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

用mermaid流程图展示信号灯的状态转换流程:

启动信号灯
初始化状态为红灯
显示红灯(60秒)
等待60秒
切换到绿灯状态
显示绿灯(50秒)
等待50秒
切换到黄灯状态
显示黄灯(10秒)
等待10秒
切换到红灯状态
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.cpptraffic_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

#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

#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

#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
# 编译器设置
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.cpporder_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改为单例:

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类加载状态:

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. 状态转换可控:状态转换规则由状态类自主控制,逻辑清晰。

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

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

http://www.dtcms.com/a/438223.html

相关文章:

  • 【计算机组成原理】深入浅出ASCII码:从历史起源到现代应用的全方位解析
  • [USACO11NOV] Cow Lineup S(黄)
  • 安卓开发学习
  • 全人源抗体制备的 “动物工厂”:转基因与嵌合小鼠技术如何突破免疫原性瓶颈?
  • 郑州网站建设报价电子商务的网站建设要求步骤
  • 做前端网站用什么软件写代码吗如何链接自己做的网站
  • 高阳网站建设网站头部通用代码
  • Ubuntu中安装Viper炫彩蛇教程(亲测可用)
  • 欢迎来到量化实战
  • 网站如何增加百度权重的方法亚马逊官网中国网页版
  • DOM 遍历
  • 《C++ STL:vector类(上)》:详解基础使用核心接口及经典算法题
  • osg中相机矩阵到vsg相机矩阵的转换
  • 怎么给网站做seo上海中风险地区什么时候能解除
  • 在IDEA中使用Git
  • IntelliJ IDEA 2025:最新使用图文教程!
  • 十二、SpringMVC
  • 公司营销型网站建设成都建站seo
  • 什么是GO语言里面的GMP调度模型?
  • Traffic Filtering 流过滤 概念及题目
  • 198种组合算法+优化BiGRU双向门控循环单元+SHAP分析+新数据预测+多输出!深度学习可解释分析,强烈安利,粉丝必备!
  • 兼职开发网站开发建设网站需要学什么
  • SQLite 简介
  • TypeScript 中的 JSX 详解
  • Codesys如何读取轴的当前控制模式
  • 高性能网站建设指南 京东模拟网站开发
  • 一元购网站建设教育类网站策划书
  • 2025 AI 落地全景:从技术热潮到产业重构
  • 解析动态数据:如何抓取 JavaScript 加载的 AJAX 内容
  • 聚焦技术落地,展现 AI 重构产业的实践路径。