C++设计模式之行为型模式:状态模式(State)
状态模式(State)是行为型设计模式的一种,它允许对象在内部状态改变时改变其行为,使对象看起来好像修改了它的类。这种模式将状态封装为独立的类,并将对象的行为委托给当前状态,从而实现状态与行为的解耦。
一、核心思想与角色
状态模式的核心是“状态决定行为”,通过将不同状态下的行为封装到对应的状态类中,使对象在切换状态时自动改变行为。其核心角色如下:
角色名称 | 核心职责 |
---|---|
环境类(Context) | 维护一个当前状态的引用,提供切换状态的接口,将行为委托给当前状态。 |
抽象状态(State) | 定义所有具体状态的公共接口,声明环境类中依赖状态的方法。 |
具体状态(ConcreteState) | 实现抽象状态接口,定义特定状态下环境类的行为,可能包含状态转换的逻辑。 |
核心思想:将对象在不同状态下的行为分离到不同的状态类中,环境类通过切换当前状态对象来改变自身行为,避免使用大量条件判断(if-else
或switch-case
)。
二、实现示例(订单状态流转)
假设我们需要设计一个电商订单系统,订单有多种状态(待支付、已支付、已发货、已完成、已取消),不同状态下支持的操作不同:
- 待支付:可支付、可取消
- 已支付:可发货、可退款(取消)
- 已发货:可确认收货
- 已完成:可评价(简化)
- 已取消:无有效操作
使用状态模式可清晰管理状态流转和对应行为:
#include <iostream>
#include <string>// 前向声明环境类
class Order;// 2. 抽象状态:订单状态
class OrderState {
public:// 纯虚方法:各种状态下的操作virtual void pay(Order* order) = 0; // 支付virtual void ship(Order* order) = 0; // 发货virtual void confirmReceipt(Order* order) = 0; // 确认收货virtual void cancel(Order* order) = 0; // 取消订单virtual std::string getStateName() = 0; // 获取状态名称virtual ~OrderState() = default;
};// 1. 环境类:订单
class Order {
private:OrderState* currentState; // 当前状态std::string orderId; // 订单ID// 切换状态(私有,仅状态类可调用)void setState(OrderState* newState) {currentState = newState;std::cout << "订单[" << orderId << "]状态变更为:" << currentState->getStateName() << std::endl;}public:Order(const std::string& id);~Order();// 订单操作(委托给当前状态)void pay() { currentState->pay(this); }void ship() { currentState->ship(this); }void confirmReceipt() { currentState->confirmReceipt(this); }void cancel() { currentState->cancel(this); }// 友元声明:允许状态类调用setStatefriend class PendingPaymentState;friend class PaidState;friend class ShippedState;friend class CompletedState;friend class CancelledState;
};// 3. 具体状态1:待支付
class PendingPaymentState : public OrderState {
public:void pay(Order* order) override;void ship(Order* order) override {std::cout << "错误:订单未支付,无法发货" << std::endl;}void confirmReceipt(Order* order) override {std::cout << "错误:订单未支付,无法确认收货" << std::endl;}void cancel(Order* order) override;std::string getStateName() override { return "待支付"; }// 单例模式:减少状态对象创建(状态无内部状态时适用)static PendingPaymentState* getInstance() {static PendingPaymentState instance;return &instance;}
};// 3. 具体状态2:已支付
class PaidState : public OrderState {
public:void pay(Order* order) override {std::cout << "错误:订单已支付,无需重复支付" << std::endl;}void ship(Order* order) override;void confirmReceipt(Order* order) override {std::cout << "错误:订单未发货,无法确认收货" << std::endl;}void cancel(Order* order) override;std::string getStateName() override { return "已支付"; }static PaidState* getInstance() {static PaidState instance;return &instance;}
};// 3. 具体状态3:已发货
class ShippedState : public OrderState {
public:void pay(Order* order) override {std::cout << "错误:订单已发货,无需支付" << std::endl;}void ship(Order* order) override {std::cout << "错误:订单已发货,无法重复发货" << std::endl;}void confirmReceipt(Order* order) override;void cancel(Order* order) override {std::cout << "错误:订单已发货,无法取消" << std::endl;}std::string getStateName() override { return "已发货"; }static ShippedState* getInstance() {static ShippedState instance;return &instance;}
};// 3. 具体状态4:已完成
class CompletedState : public OrderState {
public:void pay(Order* order) override {std::cout << "错误:订单已完成,无需支付" << std::endl;}void ship(Order* order) override {std::cout << "错误:订单已完成,无需发货" << std::endl;}void confirmReceipt(Order* order) override {std::cout << "错误:订单已完成,无需重复确认" << std::endl;}void cancel(Order* order) override {std::cout << "错误:订单已完成,无法取消" << std::endl;}std::string getStateName() override { return "已完成"; }static CompletedState* getInstance() {static CompletedState instance;return &instance;}
};// 3. 具体状态5:已取消
class CancelledState : public OrderState {
public:void pay(Order* order) override {std::cout << "错误:订单已取消,无法支付" << std::endl;}void ship(Order* order) override {std::cout << "错误:订单已取消,无法发货" << std::endl;}void confirmReceipt(Order* order) override {std::cout << "错误:订单已取消,无法确认收货" << std::endl;}void cancel(Order* order) override {std::cout << "错误:订单已取消,无需重复取消" << std::endl;}std::string getStateName() override { return "已取消"; }static CancelledState* getInstance() {static CancelledState instance;return &instance;}
};// 实现Order类的构造和析构
Order::Order(const std::string& id) : orderId(id) {// 初始状态为待支付currentState = PendingPaymentState::getInstance();std::cout << "创建订单[" << orderId << "],初始状态:" << currentState->getStateName() << std::endl;
}Order::~Order() {std::cout << "订单[" << orderId << "]处理结束" << std::endl;
}// 实现PendingPaymentState的状态转换
void PendingPaymentState::pay(Order* order) {// 待支付 → 已支付order->setState(PaidState::getInstance());
}void PendingPaymentState::cancel(Order* order) {// 待支付 → 已取消order->setState(CancelledState::getInstance());
}// 实现PaidState的状态转换
void PaidState::ship(Order* order) {// 已支付 → 已发货order->setState(ShippedState::getInstance());
}void PaidState::cancel(Order* order) {// 已支付 → 已取消(退款)order->setState(CancelledState::getInstance());
}// 实现ShippedState的状态转换
void ShippedState::confirmReceipt(Order* order) {// 已发货 → 已完成order->setState(CompletedState::getInstance());
}// 客户端代码:测试订单状态流转
int main() {// 创建订单(初始状态:待支付)Order* order = new Order("ORD-20230901-12345");// 执行一系列操作,触发状态转换std::cout << "\n=== 尝试支付 ===" << std::endl;order->pay();std::cout << "\n=== 尝试发货 ===" << std::endl;order->ship();std::cout << "\n=== 尝试确认收货 ===" << std::endl;order->confirmReceipt();std::cout << "\n=== 尝试再次支付(无效操作) ===" << std::endl;order->pay();// 另一个订单测试取消流程std::cout << "\n\n=== 测试取消流程 ===" << std::endl;Order* order2 = new Order("ORD-20230901-67890");std::cout << "\n=== 直接取消 ===" << std::endl;order2->cancel();std::cout << "\n=== 尝试支付(已取消状态) ===" << std::endl;order2->pay();// 释放资源delete order;delete order2;return 0;
}
三、代码解析
-
抽象状态(OrderState):
定义了订单的所有可能操作(pay()
、ship()
等)和获取状态名称的接口,是所有具体状态的基类。 -
具体状态:
每个状态类(如PendingPaymentState
、PaidState
)实现OrderState
接口,定义该状态下允许的操作和状态转换逻辑:- 允许的操作(如待支付状态的
pay()
)会触发状态转换(调用order->setState()
切换到新状态)。 - 不允许的操作(如待支付状态的
ship()
)会输出错误提示。 - 使用单例模式(
getInstance()
)减少状态对象的创建(状态无内部数据时适用)。
- 允许的操作(如待支付状态的
-
环境类(Order):
- 维护当前状态(
currentState
),将所有操作委托给当前状态对象(如pay()
实际调用currentState->pay(this)
)。 - 提供
setState()
方法供状态类切换状态(通过友元声明允许状态类访问)。 - 包含订单的基本信息(如
orderId
),是状态操作的上下文。
- 维护当前状态(
-
客户端使用:
客户端创建订单后,直接调用订单的操作方法(pay()
、ship()
等),无需关心当前状态,状态转换由状态类内部自动处理。
四、核心优势与适用场景
优势
- 消除条件判断:将状态相关的条件分支逻辑分散到不同状态类中,避免冗长的
if-else
或switch-case
,代码更清晰。 - 状态与行为分离:每个状态的行为封装在对应的状态类中,符合单一职责原则,便于维护和扩展。
- 简化状态转换:状态转换逻辑集中在状态类中,而非环境类,使状态流转更清晰。
- 易于扩展新状态:新增状态只需添加新的状态类,无需修改现有代码(符合开闭原则)。
适用场景
- 对象行为依赖于状态:如订单状态、游戏角色状态(存活/死亡/中毒)、设备状态(运行/暂停/停止)。
- 存在复杂状态转换:当对象有多个状态,且状态间转换规则复杂时。
- 需要避免大量条件判断:当使用条件语句管理状态导致代码难以维护时。
五、与其他模式的区别
模式 | 核心差异点 |
---|---|
状态模式 | 对象行为随状态改变而改变,状态间可相互转换,强调“状态驱动行为”。 |
策略模式 | 封装不同算法,算法间无依赖,客户端主动选择算法,强调“算法替换”。 |
享元模式 | 共享细粒度对象,关注对象复用,与状态管理无关。 |
状态模式 vs 职责链 | 状态模式中状态转换由当前状态决定,职责链中请求由第一个能处理的对象处理。 |
六、实践建议
- 状态类使用单例:当状态无内部数据时,使用单例模式减少对象创建(如示例),节省资源。
- 状态转换集中管理:状态转换逻辑可集中在环境类或专门的状态管理器中,避免状态类间过度耦合。
- 限制状态数量:状态过多会导致状态类数量激增,此时可考虑结合其他模式(如享元模式)优化。
- 明确状态流转规则:通过文档或枚举定义清晰的状态转换规则,避免状态逻辑混乱。
状态模式的核心价值在于“将状态驱动的行为模块化”,它通过分离不同状态下的行为,使系统更易于理解、扩展和维护。在需要管理复杂状态转换的场景中,状态模式能有效替代冗长的条件判断,提升代码质量。