状态模式(State)是行为型设计模式的一种,它允许对象在内部状态改变时改变其行为,使对象看起来好像修改了它的类。这种模式将状态封装为独立的类,并将对象的行为委托给当前状态,从而实现状态与行为的解耦。
一、核心思想与角色
状态模式的核心是"状态决定行为",通过将不同状态下的行为封装到对应的状态类中,使对象在切换状态时自动改变行为。其核心角色如下:
角色名称 | 核心职责 |
---|---|
环境类(Context) | 维护一个当前状态的引用,提供切换状态的接口,将行为委托给当前状态。 |
抽象状态(State) | 定义所有具体状态的公共接口,声明环境类中依赖状态的方法。 |
具体状态(ConcreteState) | 实现抽象状态接口,定义特定状态下环境类的行为,可能包含状态转换的逻辑。 |
核心思想 :将对象在不同状态下的行为分离到不同的状态类中,环境类通过切换当前状态对象来改变自身行为,避免使用大量条件判断(if-else
或switch-case
)。
二、实现示例(订单状态流转)
假设我们需要设计一个电商订单系统,订单有多种状态(待支付、已支付、已发货、已完成、已取消),不同状态下支持的操作不同:
- 待支付:可支付、可取消
- 已支付:可发货、可退款(取消)
- 已发货:可确认收货
- 已完成:可评价(简化)
- 已取消:无有效操作
使用状态模式可清晰管理状态流转和对应行为:
cpp
#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); }
// 友元声明:允许状态类调用setState
friend 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 职责链 | 状态模式中状态转换由当前状态决定,职责链中请求由第一个能处理的对象处理。 |
六、实践建议
- 状态类使用单例:当状态无内部数据时,使用单例模式减少对象创建(如示例),节省资源。
- 状态转换集中管理:状态转换逻辑可集中在环境类或专门的状态管理器中,避免状态类间过度耦合。
- 限制状态数量:状态过多会导致状态类数量激增,此时可考虑结合其他模式(如享元模式)优化。
- 明确状态流转规则:通过文档或枚举定义清晰的状态转换规则,避免状态逻辑混乱。
状态模式的核心价值在于"将状态驱动的行为模块化",它通过分离不同状态下的行为,使系统更易于理解、扩展和维护。在需要管理复杂状态转换的场景中,状态模式能有效替代冗长的条件判断,提升代码质量。