文章目录
一、状态模式的介绍
状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态改变时改变它的行为,看起来就像是对象改变了它的类一样。
通俗理解:
- 一个对象的行为依赖于它的状态(例如:登录状态 / 未登录状态)。
- 当状态发生改变时,对象表现出的行为也随之发生变化。
- 使用状态模式可以避免在对象中堆积大量的 if-else 或 switch 语句。
主要包含以下几个角色:
- Context(环境类):维护一个当前状态对象的引用。提供接口给客户端调用,并在内部把请求委托给当前的状态对象来处理。
- State(抽象状态类/接口):定义状态对象的共同接口,不同状态下的行为都需要实现这个接口。
- ConcreteState(具体状态类):实现抽象状态定义的行为。每个具体状态类实现对象在该状态下的特定行为。
状态模式结构:
二、实例分析
问题:
状态模式与有限状态机 的概念紧密相关。
其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个状态切换到另一个状态。 不过, 根据当前状态, 程序可能会切换到另外一种状态, 也可能会保持当前状态不变。 这些数量有限且预先定义的状态切换规则被称为转移。
你还可将该方法应用在对象上。 假如你有一个文档Document类。 文档可能会处于草稿Draft 、 审阅中Moderation和已发布Published三种状态中的一种。 文档的publish发布方法在不同状态下的行为略有不同:
- 处于草稿状态时, 它会将文档转移到审阅中状态。
- 处于审阅中状态时, 如果当前用户是管理员, 它会公开发布文档。
- 处于已发布状态时, 它不会进行任何操作。

状态机通常由众多条件运算符 (if或switch)实现, 可根据对象的当前状态选择相应的行为。 "状态" 通常只是对象中的一组成员变量值。 即使你之前从未听说过有限状态机, 你也很可能已经实现过状态模式。
当我们逐步在文档类中添加更多状态和依赖于状态的行为后, 基于条件语句的状态机就会暴露其最大的弱点。 为了能根据当前状态选择完成相应行为的方法, 绝大部分方法中会包含复杂的条件语句。 修改其转换逻辑可能会涉及到修改所有方法中的状态条件语句, 导致代码的维护工作非常艰难。
这个问题会随着项目进行变得越发严重。 我们很难在设计阶段预测到所有可能的状态和转换。 随着时间推移, 最初仅包含有限条件语句的简洁状态机可能会变成臃肿的一团乱麻。
解决方案:
状态模式建议为对象的所有可能状态新建一个类, 然后将所有状态的对应行为抽取到这些类中。
原始对象被称为上下文 (context), 它并不会自行实现所有行为, 而是会保存一个指向表示当前状态的状态对象的引用, 且将所有与状态相关的工作委派给该对象。

如需将上下文转换为另外一种状态, 则需将当前活动的状态对象替换为另外一个代表新状态的对象。 采用这种方式是有前提的: 所有状态类都必须遵循同样的接口, 而且上下文必须仅通过接口与这些对象进行交互。
这个结构可能看上去与策略模式相似, 但有一个关键性的不同------在状态模式中, 特定状态知道其他所有状态的存在, 且能触发从一个状态到另一个状态的转换; 策略则几乎完全不知道其他策略的存在。
三、示例代码
示例一:电梯状态
cpp
#include <iostream>
using namespace std;
// 抽象状态类
class State {
public:
virtual void handle() = 0;
virtual ~State() = default;
};
// 具体状态类 - 开门
class OpenState : public State {
public:
void handle() override {
cout << "电梯门打开..." << endl;
}
};
// 具体状态类 - 关门
class CloseState : public State {
public:
void handle() override {
cout << "电梯门关闭..." << endl;
}
};
// 环境类
class Context {
private:
State* state;
public:
Context(State* s) : state(s) {}
void setState(State* s) {
state = s;
}
void request() {
state->handle();
}
};
int main() {
// 初始状态:关门
State* close = new CloseState();
Context* ctx = new Context(close);
ctx->request();
// 切换到开门
State* open = new OpenState();
ctx->setState(open);
ctx->request();
delete close;
delete open;
delete ctx;
return 0;
}
示例二:登录状态(未登录、已登录)
cpp
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QString>
// ================== 抽象状态类 ==================
class State {
public:
virtual ~State() {}
virtual QString text() const = 0; // 按钮文字
virtual State* nextState() = 0; // 切换到下一个状态
};
// ================== 具体状态类 ==================
// 未登录
class UnLoginState : public State {
public:
QString text() const override {
return "未登录";
}
State* nextState() override;
};
// 已登录
class LoginState : public State {
public:
QString text() const override {
return "已登录";
}
State* nextState() override;
};
// 登录过期
class ExpiredState : public State {
public:
QString text() const override {
return "登录过期";
}
State* nextState() override;
};
// ================== 状态切换实现 ==================
State* UnLoginState::nextState() {
return new LoginState();
}
State* LoginState::nextState() {
return new ExpiredState();
}
State* ExpiredState::nextState() {
return new UnLoginState();
}
// ================== 主窗口类 ==================
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr) : QMainWindow(parent), m_state(new UnLoginState()) {
m_button = new QPushButton(m_state->text(), this);
m_button->setFixedSize(120, 40);
m_button->move(50, 50);
connect(m_button, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
}
~MainWindow() {
delete m_state;
}
private slots:
void onButtonClicked() {
State* newState = m_state->nextState();
delete m_state;
m_state = newState;
m_button->setText(m_state->text());
}
private:
QPushButton* m_button;
State* m_state;
};
// ================== main 函数 ==================
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.setWindowTitle("状态模式示例");
w.resize(220, 150);
w.show();
return a.exec();
}
示例三:订单状态(待支付、已支付、已发货、已完成)
cpp
#include <iostream>
#include <string>
using namespace std;
// 抽象状态类
class State {
public:
virtual ~State() {}
virtual string name() const = 0; // 状态名字
virtual State* nextState() = 0; // 切换到下一个状态
};
// 待支付
class PendingState : public State {
public:
string name() const override { return "待支付"; }
State* nextState() override; // 声明
};
// 已支付
class PaidState : public State {
public:
string name() const override { return "已支付"; }
State* nextState() override;
};
// 已发货
class ShippedState : public State {
public:
string name() const override { return "已发货"; }
State* nextState() override;
};
// 已完成
class CompletedState : public State {
public:
string name() const override { return "已完成"; }
State* nextState() override {
cout << "订单已完成,无法再改变状态。" << endl;
return this; // 保持在已完成状态
}
};
// ========== 状态切换实现 ==========
State* PendingState::nextState() { return new PaidState(); }
State* PaidState::nextState() { return new ShippedState(); }
State* ShippedState::nextState() { return new CompletedState(); }
// ========== 环境类(订单) ==========
class Order {
private:
State* state;
public:
Order() : state(new PendingState()) {}
~Order() { delete state; }
void advance() {
State* newState = state->nextState();
if (newState != state) { // 不是停留状态,说明切换了
delete state;
state = newState;
}
cout << "当前订单状态:" << state->name() << endl;
}
string status() const { return state->name(); }
};
// ========== 测试 ==========
int main() {
Order order;
cout << "初始状态:" << order.status() << endl;
order.advance(); // 待支付 -> 已支付
order.advance(); // 已支付 -> 已发货
order.advance(); // 已发货 -> 已完成
order.advance(); // 已完成 -> 仍是已完成
return 0;
}
示例四:文档审批/发布流程
cpp
#include <iostream>
#include <string>
using namespace std;
// 用户角色
enum class Role {
User,
Admin
};
// 抽象状态类
class State {
public:
virtual ~State() {}
virtual string name() const = 0;
virtual State* publish(Role role) = 0; // 状态转换逻辑
};
// ============ Draft 草稿 ============
class DraftState : public State {
public:
string name() const override { return "草稿"; }
State* publish(Role role) override;
};
// ============ Moderation 审阅中 ============
class ModerationState : public State {
public:
string name() const override { return "审阅中"; }
State* publish(Role role) override;
};
// ============ Published 已发布 ============
class PublishedState : public State {
public:
string name() const override { return "已发布"; }
State* publish(Role role) override {
cout << "文档已发布,无法进行操作。" << endl;
return this; // 保持当前状态
}
};
// ============ 状态切换实现 ============
State* DraftState::publish(Role role) {
if (role == Role::User) {
cout << "用户发表 → 转入审阅中" << endl;
return new ModerationState();
} else {
cout << "管理员直接发表 → 转入已发布" << endl;
return new PublishedState();
}
}
State* ModerationState::publish(Role role) {
if (role == Role::Admin) {
cout << "管理员批准 → 转入已发布" << endl;
return new PublishedState();
} else {
cout << "普通用户无法操作,保持在审阅中" << endl;
return this;
}
}
// ============ 文档环境类 ============
class Document {
private:
State* state;
public:
Document() : state(new DraftState()) {}
~Document() { delete state; }
void publish(Role role) {
State* newState = state->publish(role);
if (newState != state) {
delete state;
state = newState;
}
cout << "当前状态:" << state->name() << endl;
}
};
// ============ 测试 ============
int main() {
Document doc;
cout << "初始状态:草稿" << endl;
doc.publish(Role::User); // 用户发表 -> 审阅中
doc.publish(Role::User); // 普通用户无权发布 -> 仍然审阅中
doc.publish(Role::Admin); // 管理员批准 -> 已发布
doc.publish(Role::Admin); // 已发布 -> 无操作
return 0;
}
示例五:智能手机按键的状态机
需求分析:
- 解锁状态:按下按键 → 执行各种功能(比如打开相机、拨号等)。
- 锁定状态:按下按键 → 解锁屏幕。
- 电量不足状态:按下按键 → 显示充电页面。
cpp
#include <iostream>
#include <string>
using namespace std;
// 抽象状态类
class State {
public:
virtual ~State() {}
virtual void onPress() = 0; // 按下按键行为
};
// ========== 具体状态类 ==========
// 解锁状态
class UnlockedState : public State {
public:
void onPress() override {
cout << "已解锁:执行按键功能(如打开相机、拨号)" << endl;
}
};
// 锁定状态
class LockedState : public State {
public:
void onPress() override {
cout << "处于锁定:按键 → 解锁屏幕" << endl;
}
};
// 电量不足状态
class LowBatteryState : public State {
public:
void onPress() override {
cout << "电量不足:按键 → 显示充电页面" << endl;
}
};
// ========== 环境类(智能手机) ==========
class Smartphone {
private:
State* state;
public:
Smartphone(State* initState) : state(initState) {}
~Smartphone() { delete state; }
void setState(State* newState) {
delete state;
state = newState;
}
void pressButton() {
state->onPress();
}
};
// ========== 测试 ==========
int main() {
// 初始状态:锁定
Smartphone phone(new LockedState());
phone.pressButton(); // 锁定 → 解锁屏幕
phone.setState(new UnlockedState());
phone.pressButton(); // 解锁 → 执行功能
phone.setState(new LowBatteryState());
phone.pressButton(); // 电量不足 → 显示充电页面
return 0;
}