状态模式在订单流程中避免if-else膨胀,使order不感知状态细节;状态类用裸指针引用order,由transition_to安全切换,数据统一存于order,虚函数首行校验上下文,迁移逻辑内置于状态类。

状态模式在订单流程中不是“必须用”,而是“不用就容易写成一长串 if-else 或 switch,且每次加状态都要改主逻辑”。它真正起作用的地方,是让 Order 类不感知状态细节,把「能做什么」「怎么过渡」完全下放到具体状态类里。
状态类必须持有对上下文(Order)的非拥有引用
常见错误是让 OrderState 持有 std::shared_ptr<order></order>,结果引发循环引用——Order 持有当前状态,状态又持有 Order,两者生命周期锁死,析构失败。更糟的是,某些状态(比如已取消)不该再触发任何业务操作,但若引用强持有,就可能误调用。
- 用
Order*(裸指针)最稳妥:状态只读/调用Order的公开方法,不参与其生命周期管理 - 构造状态时传入
this(即Order*),不拷贝、不共享 - 在
Order析构前,确保m_state被置为nullptr或重置为安全状态(如new IdleState(this)) - 所有状态类的虚函数(如
pay()、ship())内部,第一行建议加if (!m_context) return;防空解引用
状态切换必须由当前状态主动发起,而非 Order 控制
很多人把状态变更写在 Order::pay() 里:m_state = std::make_unique<paidstate>(this)</paidstate>——这破坏了状态自治原则。一旦后续新增校验逻辑(比如“仅未发货订单可支付”),就得去改 Order::pay(),而不是只动 CreatedState::pay()。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
Order只暴露接口如pay()、cancel(),这些函数内部只调用m_state->pay() - 每个状态子类决定自己能否响应:比如
ShippedState::pay()直接返回或抛std::logic_error("already shipped") - 状态迁移发生在状态内部:比如
CreatedState::pay()完成支付逻辑后,调用m_context->transition_to(new PaidState(m_context)) -
transition_to()是Order的一个受保护方法,负责清理旧状态、接管新状态,避免裸指针悬挂
避免在状态类中缓存业务数据,所有状态共享同一份 Order 成员
有人为图方便,在 PaidState 里加个 m_payment_time,在 ShippedState 里加 m_shipped_by……很快就会发现:状态切换时这些字段丢失、重复初始化、或者某个状态想读另一个状态写过的值却读不到。
- 所有与订单相关的数据(如
status_str、payment_time、tracking_number)必须定义在Order类中 - 状态类只负责行为逻辑,通过
m_context->get_payment_time()或m_context->set_shipped_by("xxx")访问 - 如果某字段只在特定状态下合法(如
tracking_number仅发货后存在),就在Order中用std::optional<:string></:string>存储,并在对应状态的ship()里赋值 - 这样既保证数据一致性,也方便日志、序列化、审计时统一取数
transition_to() 必须处理异常安全与多线程竞争
生产环境里,订单可能被多个服务并发调用(比如支付回调和客服强制取消同时到达)。如果 transition_to() 先 delete 旧状态、再 new 新状态,中间发生异常,m_state 就成悬垂指针;若没加锁,还可能两个线程同时写 m_state,造成内存泄漏或 double-delete。
- 用
std::unique_ptr<orderstate></orderstate>管理状态生命周期,transition_to()接收std::unique_ptr<orderstate>&&</orderstate> - 内部用
std::lock_guard<:mutex></:mutex>包裹状态替换逻辑(注意:锁粒度别扩大到整个业务逻辑,只锁状态指针本身) - 新状态构造成功后再交换:先
auto new_state = std::move(new_state_ptr),再m_state = std::move(new_state),确保强异常安全 - 测试时模拟并发调用
pay()和cancel(),观察是否出现double-free或状态错乱
最难的不是写完五个状态类,而是当产品说“退款要支持部分退、且退完还能补发”时,你得判断该在 ShippedState 里拆出 PartiallyRefundedState,还是让 RefundState 内部维护一个退了多少的计数——这时候,状态类之间能不能通信、要不要引入事件总线,才是真正考验设计的地方。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










