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

​【C++设计模式】第十九篇:状态模式(State)

注意:复现代码时,确保 VS2022 使用 C++17/20 标准以支持现代特性。

对象行为的动态切换


1. 模式定义与用途

核心思想

  • ​状态模式:允许对象在其内部状态改变时改变行为,将状态逻辑封装为独立的类,使状态转换显式化。
  • ​关键用途
    ​1.替代条件分支:消除复杂的if-elseswitch-case结构。
    ​2.简化状态迁移:每个状态类仅关注自身行为及转换条件。
    ​3.动态切换行为:运行时通过切换状态对象改变对象行为。

经典场景

  • 电梯控制系统(停止、运行、故障状态)。
  • 订单生命周期(待支付、已发货、已完成)。
  • 游戏角色状态(移动、攻击、防御)。

2. 模式结构解析

UML类图

+---------------------+          +---------------------+  
|      Context        |          |       State         |  
+---------------------+          +---------------------+  
| - state: State      |<>------->| + handle(): void    |  
+---------------------+          +---------------------+  
| + setState(s: State)|                    ^  
| + request()         |                    |  
+---------------------+            +-------+-------+  
                                    |               |  
                          +----------------+ +----------------+  
                          | ConcreteStateA | | ConcreteStateB |  
                          +----------------+ +----------------+  
                          | + handle()     | | + handle()     |  
                          +----------------+ +----------------+  

角色说明

  1. Context:上下文,维护当前状态对象,定义客户端接口(如request())。
  2. State:抽象状态接口,定义状态行为(如handle())。
  3. ConcreteState:具体状态类,实现特定状态的行为与转换逻辑。

3. 现代C++实现示例

场景:电梯状态控制

​步骤1:定义状态接口与上下文
#include <iostream>  
#include <memory>  

class Elevator;  // 前向声明  

// 抽象状态  
class ElevatorState {  
public:  
    virtual ~ElevatorState() = default;  
    virtual void openDoors(Elevator* elevator) = 0;  
    virtual void closeDoors(Elevator* elevator) = 0;  
    virtual void move(Elevator* elevator) = 0;  
};  

// 上下文:电梯  
class Elevator {  
public:  
    Elevator();  
    void setState(std::unique_ptr<ElevatorState> state);  

    // 客户端接口  
    void pressOpenButton() { state_->openDoors(this); }  
    void pressCloseButton() { state_->closeDoors(this); }  
    void pressMoveButton() { state_->move(this); }  

private:  
    std::unique_ptr<ElevatorState> state_;  
};  
步骤2:实现具体状态类
// 停止状态  
class StoppedState : public ElevatorState {  
public:  
    void openDoors(Elevator* elevator) override {  
        std::cout << "门已打开\n";  
        elevator->setState(std::make_unique<OpenState>());  
    }  

    void closeDoors(Elevator* elevator) override {  
        std::cout << "门已关闭\n";  
    }  

    void move(Elevator* elevator) override {  
        std::cout << "电梯开始移动\n";  
        elevator->setState(std::make_unique<MovingState>());  
    }  
};  

// 开门状态  
class OpenState : public ElevatorState {  
public:  
    void openDoors(Elevator*) override {  
        std::cout << "错误:门已经是开着的\n";  
    }  

    void closeDoors(Elevator* elevator) override {  
        std::cout << "门已关闭\n";  
        elevator->setState(std::make_unique<StoppedState>());  
    }  

    void move(Elevator*) override {  
        std::cout << "错误:门未关闭,无法移动\n";  
    }  
};  

// 移动状态  
class MovingState : public ElevatorState {  
public:  
    void openDoors(Elevator*) override {  
        std::cout << "错误:移动中不能开门\n";  
    }  

    void closeDoors(Elevator*) override {  
        std::cout << "错误:门已经是关着的\n";  
    }  

    void move(Elevator* elevator) override {  
        std::cout << "电梯停止移动\n";  
        elevator->setState(std::make_unique<StoppedState>());  
    }  
};  

// 上下文初始化  
Elevator::Elevator() : state_(std::make_unique<StoppedState>()) {}  

void Elevator::setState(std::unique_ptr<ElevatorState> state) {  
    state_ = std::move(state);  
}  
步骤3:客户端代码
int main() {  
    Elevator elevator;  

    elevator.pressMoveButton();  // 移动  
    elevator.pressOpenButton();  // 错误:移动中不能开门  
    elevator.pressMoveButton();   // 停止移动  
    elevator.pressOpenButton();   // 开门  
    elevator.pressCloseButton();  // 关门  
}  

/* 输出:  
电梯开始移动  
错误:移动中不能开门  
电梯停止移动  
门已打开  
门已关闭  
*/  

4. 应用场景示例

场景1:订单状态流转

class Order;  

class OrderState {  
public:  
    virtual void pay(Order* order) = 0;  
    virtual void ship(Order* order) = 0;  
    virtual void complete(Order* order) = 0;  
};  

class Order {  
public:  
    Order();  
    void setState(std::unique_ptr<OrderState> state);  
    void processPayment() { state_->pay(this); }  
    // ...其他操作  
};  

// 具体状态:待支付  
class UnpaidState : public OrderState {  
    void pay(Order* order) override {  
        std::cout << "订单已支付\n";  
        order->setState(std::make_unique<PaidState>());  
    }  
    // ...其他方法抛出异常或忽略  
};  
场景2:游戏角色状态切换
class Character;  

class CharacterState {  
public:  
    virtual void move(Character* character) = 0;  
    virtual void attack(Character* character) = 0;  
};  

class IdleState : public CharacterState {  
    void move(Character* c) override {  
        c->setState(std::make_unique<MovingState>());  
    }  
    void attack(Character*) override { /* 待机状态无法攻击 */ }  
};  

5. 优缺点分析

​优点​缺点
消除复杂条件分支,提升可读性增加类的数量(每个状态对应一个类)
状态转换逻辑集中管理状态较多时类间关系复杂化
符合开闭原则(新增状态无需修改现有代码)上下文需持有所有状态类的引用

6. 调试与优化策略

调试技巧(VS2022)​

1. ​跟踪状态转换:
  • 在setState()方法内设置断点,观察状态切换是否符合预期。
2. ​状态日志记录:
void Order::setState(std::unique_ptr<OrderState> state) {  
    std::cout << "状态切换至: " << typeid(*state).name() << "\n";  
    state_ = std::move(state);  
}  

性能优化

1. 状态对象复用:
  • 使用对象池共享状态实例(若状态无内部数据)。
class StatePool {  
public:  
    static StoppedState& getStoppedState() {  
        static StoppedState instance;  
        return instance;  
    }  
};  
2. ​避免频繁状态切换:
  • 合并相邻状态或延迟状态切换(如批量处理事件)。

http://www.kler.cn/a/581547.html

相关文章:

  • 备赛蓝桥杯之第XX届职业院校组省赛第七题:Github 明星项目统计
  • 买瓜 第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 A 组
  • 常用的接口重试方案!
  • JAVASE(五)
  • 【BUG】类文件具有错误的版本 61.0, 应为 52.0,请删除该文件或确保该文件位于正确的类路径子目录中。
  • Datawhale AI + 办公 笔记2
  • Spring Boot 调用DeepSeek API的详细教程
  • AI自动化代码编程——IntelliJ IDEA安装Continue框架使用 DeepSeek
  • vite 创建Vue3自定义指令集合插件,并发布npm
  • 2.3 DeepSeek SDK接入与鉴权体系设计
  • 【DuodooTEKr】 基于Python+OCR+DeepSeek的英国购物小票识别系统开发实战
  • 【实战ES】实战 Elasticsearch:快速上手与深度实践-6.1.2TLS加密通信配置
  • 系统架构设计师知识小科普:系统架构评估
  • C++ 入门
  • linux自启动服务
  • VMware Workstation Pro 上安装rockylinux虚拟机
  • 【数码科技】文心一言4.0 VS DEEPSEEK V3
  • Django模板语法及静态文件
  • 03 | fastgo 项目规范及目录结构介绍
  • C语言每日一练——day_4