状态模式(State Pattern)——网络连接场景的 C++ 实战

发布于:2025-09-08 ⋅ 阅读:(23) ⋅ 点赞:(0)

一、为什么要用状态模式?

在开发中,经常遇到“对象在不同状态下行为不同”的情况。最常见的写法是用一堆 if/elseswitch 来判断状态,然后在不同分支里写逻辑。这样做有两个问题:

  1. 状态增多后,条件分支会变得臃肿。

  2. 修改或扩展某个状态逻辑时,可能要在多个地方改代码。

状态模式的核心思想是:

  • 把“状态”抽象成独立的类,每个状态只关心自己能做什么。

  • 上下文对象(这里是 NetworkConnection)只需要把调用转发给当前状态。

  • 状态对象在需要时可以切换上下文的状态。

这样就能让分支逻辑“消失”,变成结构清晰的多态调用。

二、场景说明

网络连接的三个状态:

  • Disconnected:允许调用 connect(),否则提示非法操作。

  • Connecting:连接过程中,connect()disconnect() 都无效,必须等待连接结果。

  • Connected:允许 send() 数据,也可以 disconnect() 主动断开。

三、类图

四、C++ 实现代码

这段代码完整实现了一个简化的 网络连接状态机

  • NetworkConnection 作为上下文类,持有当前状态对象,并对外提供统一的接口(connectdisconnectsendonConnectResult)。

  • DisconnectedConnectingConnected 三个状态类分别封装了各自的行为逻辑。

  • 状态之间的切换由状态类自身触发,例如 Disconnected 调用 connect() 会进入 Connecting,而 Connecting 根据 onConnectResult() 的结果进入 Connected 或回到 Disconnected

通过这种方式,代码避免了大量的 if/else 判断,让状态逻辑更加清晰,扩展新状态时也更加方便。

#include <iostream>
#include <memory>
#include <string>

class NetworkConnection; // 前向声明

// 状态接口
struct State {
    virtual ~State() = default;
    virtual void connect(NetworkConnection& nc) = 0;
    virtual void disconnect(NetworkConnection& nc) = 0;
    virtual void send(NetworkConnection& nc, const std::string& data) = 0;
    virtual void onConnectResult(NetworkConnection& nc, bool success) = 0;
};

// 上下文类
class NetworkConnection {
public:
    NetworkConnection();

    void connect() { currentState->connect(*this); }
    void disconnect() { currentState->disconnect(*this); }
    void send(const std::string& data) { currentState->send(*this, data); }
    void onConnectResult(bool success) { currentState->onConnectResult(*this, success); }

    void setState(std::unique_ptr<State> s) { currentState = std::move(s); }

private:
    std::unique_ptr<State> currentState;
};

// 具体状态:未连接
struct Disconnected : State {
    void connect(NetworkConnection& nc) override;
    void disconnect(NetworkConnection& nc) override {
        std::cout << "[Disconnected] 已经处于未连接状态。\n";
    }
    void send(NetworkConnection& nc, const std::string& data) override {
        std::cout << "[Disconnected] 无法发送数据,尚未连接。\n";
    }
    void onConnectResult(NetworkConnection& nc, bool success) override {
        std::cout << "[Disconnected] 忽略连接结果(当前未连接)。\n";
    }
};

// 具体状态:连接中
struct Connecting : State {
    void connect(NetworkConnection& nc) override {
        std::cout << "[Connecting] 正在连接中,不能重复连接。\n";
    }
    void disconnect(NetworkConnection& nc) override {
        std::cout << "[Connecting] 连接进行中,不能断开。\n";
    }
    void send(NetworkConnection& nc, const std::string& data) override {
        std::cout << "[Connecting] 连接尚未建立,无法发送。\n";
    }
    void onConnectResult(NetworkConnection& nc, bool success) override;
};

// 具体状态:已连接
struct Connected : State {
    void connect(NetworkConnection& nc) override {
        std::cout << "[Connected] 已经处于连接状态。\n";
    }
    void disconnect(NetworkConnection& nc) override {
        std::cout << "[Connected] 主动断开连接。\n";
        nc.setState(std::make_unique<Disconnected>());
    }
    void send(NetworkConnection& nc, const std::string& data) override {
        std::cout << "[Connected] 发送数据:" << data << "\n";
    }
    void onConnectResult(NetworkConnection& nc, bool success) override {
        std::cout << "[Connected] 忽略连接结果(已经连接)。\n";
    }
};

// --- 状态切换逻辑实现 ---
void Disconnected::connect(NetworkConnection& nc) {
    std::cout << "[Disconnected] 尝试连接...\n";
    nc.setState(std::make_unique<Connecting>());
}

void Connecting::onConnectResult(NetworkConnection& nc, bool success) {
    if (success) {
        std::cout << "[Connecting] 连接成功,进入已连接状态。\n";
        nc.setState(std::make_unique<Connected>());
    } else {
        std::cout << "[Connecting] 连接失败,回到未连接状态。\n";
        nc.setState(std::make_unique<Disconnected>());
    }
}

// --- NetworkConnection 构造 ---
NetworkConnection::NetworkConnection() {
    setState(std::make_unique<Disconnected>());
}

// --- 演示程序 ---
int main() {
    NetworkConnection nc;

    nc.send("test");          // 未连接 -> 拒绝
    nc.connect();             // Disconnected -> Connecting
    nc.connect();             // Connecting -> 拒绝重复
    nc.onConnectResult(true); // 成功 -> Connected
    nc.send("hello world");   // 已连接 -> 可发送
    nc.disconnect();          // -> Disconnected
    nc.onConnectResult(false);// 忽略(已断开)

    return 0;
}

输出示例

[Disconnected] 无法发送数据,尚未连接。
[Disconnected] 尝试连接...
[Connecting] 正在连接中,不能重复连接。
[Connecting] 连接成功,进入已连接状态。
[Connected] 发送数据:hello world
[Connected] 主动断开连接。
[Disconnected] 忽略连接结果(当前未连接)。

这个示例里用 onConnectResult(bool success) 来模拟网络异步回调,简化成一个直接调用的方法,方便演示状态切换的效果。
在真实项目中,这个函数可能是 事件回调信号槽,并不是手动调用的,而是网络库触发的。

比如在 Qt 中,QTcpSocket::connected()QTcpSocket::errorOccurred() 信号就对应了这种结果通知。

五、总结

通过状态模式,我们把“未连接 / 连接中 / 已连接”三种状态的行为逻辑清晰地分散到不同类中,而不是塞在一堆 if/else 里。这样带来的好处是:

  • 可读性高:逻辑一目了然,每个状态类只关心自己能做什么。

  • 易扩展:如果未来需要加 ReconnectingLimited 状态,只需要新增一个状态类。

  • 符合开闭原则:不需要修改原有状态类,就能添加新状态。


网站公告

今日签到

点亮在社区的每一天
去签到