【C++】状态模式

目录

  • 一、模式核心概念与结构
  • 二、C++ 实现示例:自动售货机状态管理
  • 三、状态模式的关键特性
  • 四、应用场景
  • 五、状态模式与其他设计模式的关系
  • 六、C++ 标准库中的状态模式应用
  • 七、优缺点分析
  • 八、实战案例:TCP 连接状态管理
  • 九、实现注意事项
    • 如果这篇文章对你有所帮助,渴望获得你的一个点赞!

状态模式(State Pattern)是一种【行为型】设计模式,它允许对象在其内部状态发生变化时改变其行为,看起来就像该对象改变了它的类一样。这种模式将状态相关的行为封装在独立的状态类中,并将状态转换逻辑集中管理,使系统更易于维护和扩展。

一、模式核心概念与结构

状态模式包含三个核心角色:

  1. 上下文(Context):定义客户端感兴趣的接口,维护一个当前状态的引用。
  2. 状态接口(State):定义特定状态下的行为接口,所有具体状态类必须实现该接口。
  3. 具体状态(Concrete State):实现状态接口,封装与特定状态相关的行为,并负责状态转换。

二、C++ 实现示例:自动售货机状态管理

以下是一个自动售货机的示例,演示如何使用状态模式管理不同状态下的行为:

#include 
#include 
#include 

// 前向声明
class VendingMachine;

// 状态接口
class State {
public:
    virtual ~State() = default;
    virtual void insertMoney(VendingMachine* machine, double amount) = 0;
    virtual void selectProduct(VendingMachine* machine, const std::string& product) = 0;
    virtual void dispense(VendingMachine* machine) = 0;
    virtual void cancel(VendingMachine* machine) = 0;
    virtual std::string getStateName() const = 0;
};

// 上下文:自动售货机
class VendingMachine {
private:
    std::shared_ptr<State> currentState;
    double balance;
    std::string selectedProduct;
    double productPrice;

public:
    VendingMachine();
    
    void setState(std::shared_ptr<State> state) {
        currentState = state;
        std::cout << "State changed to: " << currentState->getStateName() << std::endl;
    }
    
    void insertMoney(double amount) {
        currentState->insertMoney(this, amount);
    }
    
    void selectProduct(const std::string& product) {
        currentState->selectProduct(this, product);
    }
    
    void dispense() {
        currentState->dispense(this);
    }
    
    void cancel() {
        currentState->cancel(this);
    }
    
    double getBalance() const { return balance; }
    void setBalance(double amount) { balance = amount; }
    
    std::string getSelectedProduct() const { return selectedProduct; }
    void setSelectedProduct(const std::string& product) { selectedProduct = product; }
    
    double getProductPrice() const { return productPrice; }
    void setProductPrice(double price) { productPrice = price; }
};

// 具体状态:待机状态
class IdleState : public State {
public:
    void insertMoney(VendingMachine* machine, double amount) override {
        machine->setBalance(amount);
        std::cout << "Money inserted: " << amount << std::endl;
        machine->setState(std::make_shared<HasMoneyState>());
    }
    
    void selectProduct(VendingMachine* machine, const std::string& product) override {
        std::cout << "Please insert money first" << std::endl;
    }
    
    void dispense(VendingMachine* machine) override {
        std::cout << "No product selected and no money inserted" << std::endl;
    }
    
    void cancel(VendingMachine* machine) override {
        std::cout << "No transaction to cancel" << std::endl;
    }
    
    std::string getStateName() const override { return "Idle"; }
};

// 具体状态:已投币状态
class HasMoneyState : public State {
public:
    void insertMoney(VendingMachine* machine, double amount) override {
        double newBalance = machine->getBalance() + amount;
        machine->setBalance(newBalance);
        std::cout << "Additional money inserted: " << amount << std::endl;
        std::cout << "Current balance: " << newBalance << std::endl;
    }
    
    void selectProduct(VendingMachine* machine, const std::string& product) override {
        double price = 1.5;  // 假设所有产品价格为1.5元
        machine->setSelectedProduct(product);
        machine->setProductPrice(price);
        
        std::cout << "Product selected: " << product << ", Price: " << price << std::endl;
        
        if (machine->getBalance() >= price) {
            machine->setState(std::make_shared<ReadyToDispenseState>());
        } else {
            std::cout << "Insufficient balance. Please insert " 
                      << (price - machine->getBalance()) << " more" << std::endl;
        }
    }
    
    void dispense(VendingMachine* machine) override {
        std::cout << "Please select a product first" << std::endl;
    }
    
    void cancel(VendingMachine* machine) override {
        std::cout << "Transaction cancelled. Returning " << machine->getBalance() << std::endl;
        machine->setBalance(0);
        machine->setState(std::make_shared<IdleState>());
    }
    
    std::string getStateName() const override { return "HasMoney"; }
};

// 具体状态:准备出货状态
class ReadyToDispenseState : public State {
public:
    void insertMoney(VendingMachine* machine, double amount) override {
        double newBalance = machine->getBalance() + amount;
        machine->setBalance(newBalance);
        std::cout << "Additional money inserted: " << amount << std::endl;
        std::cout << "Current balance: " << newBalance << std::endl;
    }
    
    void selectProduct(VendingMachine* machine, const std::string& product) override {
        double price = 1.5;
        machine->setSelectedProduct(product);
        machine->setProductPrice(price);
        std::cout << "Product updated: " << product << ", Price: " << price << std::endl;
    }
    
    void dispense(VendingMachine* machine) override {
        double price = machine->getProductPrice();
        double balance = machine->getBalance();
        
        std::cout << "Dispensing " << machine->getSelectedProduct() << std::endl;
        std::cout << "Returning change: " << (balance - price) << std::endl;
        
        machine->setBalance(0);
        machine->setSelectedProduct("");
        machine->setState(std::make_shared<IdleState>());
    }
    
    void cancel(VendingMachine* machine) override {
        std::cout << "Transaction cancelled. Returning " << machine->getBalance() << std::endl;
        machine->setBalance(0);
        machine->setSelectedProduct("");
        machine->setState(std::make_shared<IdleState>());
    }
    
    std::string getStateName() const override { return "ReadyToDispense"; }
};

// 初始化自动售货机
VendingMachine::VendingMachine() {
    currentState = std::make_shared<IdleState>();
    balance = 0;
    selectedProduct = "";
    productPrice = 0;
}

// 客户端代码
int main() {
    // 创建自动售货机
    auto vendingMachine = std::make_shared<VendingMachine>();
    
    // 场景1:投币不足,取消交易
    std::cout << "=== Scenario 1 ===" << std::endl;
    vendingMachine->insertMoney(1.0);
    vendingMachine->selectProduct("Coke");
    vendingMachine->cancel();
    
    std::cout << "\n";
    
    // 场景2:投币足够,购买成功
    std::cout << "=== Scenario 2 ===" << std::endl;
    vendingMachine->insertMoney(2.0);
    vendingMachine->selectProduct("Chips");
    vendingMachine->dispense();
    
    std::cout << "\n";
    
    // 场景3:投币不足,追加投币,购买成功
    std::cout << "=== Scenario 3 ===" << std::endl;
    vendingMachine->insertMoney(1.0);
    vendingMachine->selectProduct("Water");
    vendingMachine->insertMoney(1.0);
    vendingMachine->dispense();
    
    return 0;
}

三、状态模式的关键特性

  1. 状态封装
    • 将特定状态的行为封装在独立的状态类中,使状态相关的代码集中管理。
  2. 状态转换
    • 状态类负责自身的状态转换逻辑,避免上下文类中出现复杂的条件语句。
  3. 行为随状态变化
    • 对象的行为会根据其内部状态的变化而自动调整。
  4. 符合开闭原则
    • 新增状态类无需修改现有代码,只需扩展系统。

四、应用场景

  1. 工作流系统
    • 处理对象在不同状态下的行为(如订单状态、审批流程)。
    • 例如,电商系统中订单状态的变化(待支付、已支付、已发货、已完成)。
  2. 游戏开发
    • 管理游戏角色或对象的状态(如待机、移动、攻击、死亡)。
  3. 状态机实现
    • 实现复杂的状态转换逻辑(如网络协议状态、编译器状态)。
  4. UI 组件状态管理
    • 处理 UI 组件在不同状态下的显示和交互(如按钮的启用 / 禁用、加载状态)。

五、状态模式与其他设计模式的关系

  1. 策略模式
    • 状态模式和策略模式结构相似,但意图不同。状态模式强调对象状态的变化,而策略模式强调算法的替换。
  2. 享元模式
    • 可以使用享元模式共享状态对象,减少内存开销。
  3. 观察者模式
    • 状态变化时可以使用观察者模式通知其他对象。

六、C++ 标准库中的状态模式应用

  1. 流状态
    • std::iostream的状态(如good()eof()fail())可以看作是状态模式的应用。
  2. 智能指针状态
    • std::shared_ptr的引用计数状态影响其行为。
  3. 正则表达式引擎
    • 正则表达式匹配过程中的状态转换。

七、优缺点分析

优点:

  • 结构清晰:避免大量条件语句,使代码更易维护。
  • 可扩展性:新增状态只需添加新的状态类,符合开闭原则。
  • 封装性:状态相关行为封装在状态类中,提高了内聚性。
  • 简化状态转换:状态转换逻辑集中在状态类中,便于管理。

缺点:

  • 类数量增加:每个状态都需要一个独立的类,可能导致类爆炸。
  • 状态转换耦合:状态类之间可能存在依赖关系,增加了系统复杂度。
  • 学习曲线:对于简单状态机,使用状态模式可能显得过于复杂。

八、实战案例:TCP 连接状态管理

以下是一个 TCP 连接状态管理的实现示例,演示如何使用状态模式处理不同连接状态:

#include 
#include 
#include 

// 前向声明
class TCPConnection;

// 状态接口
class TCPState {
public:
    virtual ~TCPState() = default;
    virtual void open(TCPConnection* connection) = 0;
    virtual void close(TCPConnection* connection) = 0;
    virtual void send(TCPConnection* connection, const std::string& data) = 0;
    virtual std::string getStateName() const = 0;
};

// 上下文:TCP连接
class TCPConnection {
private:
    std::shared_ptr<TCPState> currentState;

public:
    TCPConnection();
    
    void setState(std::shared_ptr<TCPState> state) {
        currentState = state;
        std::cout << "Connection state changed to: " << currentState->getStateName() << std::endl;
    }
    
    void open() {
        currentState->open(this);
    }
    
    void close() {
        currentState->close(this);
    }
    
    void send(const std::string& data) {
        currentState->send(this, data);
    }
};

// 具体状态:关闭状态
class TCPClosed : public TCPState {
public:
    void open(TCPConnection* connection) override {
        std::cout << "Opening connection..." << std::endl;
        // 执行打开连接的操作
        connection->setState(std::make_shared<TCPOpen>());
    }
    
    void close(TCPConnection* connection) override {
        std::cout << "Connection is already closed" << std::endl;
    }
    
    void send(TCPConnection* connection, const std::string& data) override {
        std::cout << "Cannot send data. Connection is closed" << std::endl;
    }
    
    std::string getStateName() const override { return "Closed"; }
};

// 具体状态:打开状态
class TCPOpen : public TCPState {
public:
    void open(TCPConnection* connection) override {
        std::cout << "Connection is already open" << std::endl;
    }
    
    void close(TCPConnection* connection) override {
        std::cout << "Closing connection..." << std::endl;
        // 执行关闭连接的操作
        connection->setState(std::make_shared<TCPClosed>());
    }
    
    void send(TCPConnection* connection, const std::string& data) override {
        std::cout << "Sending data: " << data << std::endl;
        // 执行数据发送的操作
        connection->setState(std::make_shared<TCPListen>());
    }
    
    std::string getStateName() const override { return "Open"; }
};

// 具体状态:监听状态
class TCPListen : public TCPState {
public:
    void open(TCPConnection* connection) override {
        std::cout << "Connection is already open. Cannot open again while listening" << std::endl;
    }
    
    void close(TCPConnection* connection) override {
        std::cout << "Closing connection..." << std::endl;
        // 执行关闭连接的操作
        connection->setState(std::make_shared<TCPClosed>());
    }
    
    void send(TCPConnection* connection, const std::string& data) override {
        std::cout << "Cannot send data while in listening state" << std::endl;
    }
    
    std::string getStateName() const override { return "Listen"; }
};

// 初始化TCP连接
TCPConnection::TCPConnection() {
    currentState = std::make_shared<TCPClosed>();
}

// 客户端代码
int main() {
    // 创建TCP连接
    auto connection = std::make_shared<TCPConnection>();
    
    // 尝试发送数据(连接已关闭)
    connection->send("Hello");
    
    // 打开连接
    connection->open();
    
    // 发送数据
    connection->send("Hello, world!");
    
    // 尝试再次打开连接
    connection->open();
    
    // 关闭连接
    connection->close();
    
    // 尝试发送数据(连接已关闭)
    connection->send("Goodbye");
    
    return 0;
}

九、实现注意事项

  1. 状态初始化
    • 上下文类应在初始化时设置初始状态。
  2. 状态转换逻辑
    • 状态转换逻辑可以放在状态类中(如示例),也可以集中在上下文类中,具体取决于业务需求。
  3. 状态共享
    • 如果状态对象不包含实例变量,可以使用单例模式或享元模式共享状态对象。
  4. 避免循环依赖
    • 状态类与上下文类可能存在循环依赖,可使用前向声明解决。

状态模式是 C++ 中处理复杂状态逻辑的有效工具,通过将状态相关行为封装在独立的类中,使系统更具灵活性和可维护性,特别适合需要根据状态动态改变行为的场景。


如果这篇文章对你有所帮助,渴望获得你的一个点赞!

【C++】状态模式_第1张图片

你可能感兴趣的:(设计模式,c++,状态模式,设计模式)