狀態模式(State Pattern)是一種行為設計模式,它允許一個對象在內部狀態改變時改變其行為,使對象看起來像是改變了其類。
核心概念
設計原則
狀態模式遵循以下設計原則:
-
單一職責原則:將狀態相關行為分離到不同類中
-
開閉原則:可以新增狀態而不修改現有代碼
-
封裝性:狀態轉換邏輯封裝在狀態類中
主要優點
-
清晰狀態轉換:將狀態轉換邏輯組織化
-
減少條件語句:消除龐大的條件狀態判斷
-
可擴展性:容易添加新狀態和轉換
-
行為局部化:狀態特定行為集中在對應狀態類中
模式結構
主要組件
-
Context(上下文)
-
維護當前狀態的引用
-
將狀態相關請求委托給當前狀態對象
-
-
State(狀態接口)
-
定義狀態接口
-
封裝與Context特定狀態相關的行為
-
-
ConcreteState(具體狀態)
-
實現狀態接口
-
每個子類實現與Context狀態相關的行為
-
完整代碼示例
#include <iostream>
#include <memory>
#include <string>// 前置聲明
class State;// ==================== 上下文類 ====================
class Player {std::unique_ptr<State> state_;std::string name_;public:explicit Player(const std::string& name);void setState(std::unique_ptr<State> state);std::string getName() const;// 玩家行為void play();void pause();void stop();void lock();void unlock();
};// ==================== 狀態接口 ====================
class State {
public:virtual ~State() = default;virtual void play(Player* player) = 0;virtual void pause(Player* player) = 0;virtual void stop(Player* player) = 0;virtual void lock(Player* player) = 0;virtual void unlock(Player* player) = 0;protected:void changeState(Player* player, std::unique_ptr<State> state) {player->setState(std::move(state));}
};// ==================== 具體狀態 ====================
class ReadyState : public State {
public:void play(Player* player) override;void pause(Player* player) override { /* 無效操作 */ }void stop(Player* player) override { /* 無效操作 */ }void lock(Player* player) override;void unlock(Player* player) override { /* 已在解鎖狀態 */ }
};class PlayingState : public State {
public:void play(Player* player) override { /* 已在播放狀態 */ }void pause(Player* player) override;void stop(Player* player) override;void lock(Player* player) override;void unlock(Player* player) override { /* 無效操作 */ }
};class PausedState : public State {
public:void play(Player* player) override;void pause(Player* player) override { /* 已在暫停狀態 */ }void stop(Player* player) override;void lock(Player* player) override;void unlock(Player* player) override { /* 無效操作 */ }
};class LockedState : public State {
public:void play(Player* player) override { /* 鎖定狀態下不能播放 */ }void pause(Player* player) override { /* 鎖定狀態下不能暫停 */ }void stop(Player* player) override { /* 鎖定狀態下不能停止 */ }void lock(Player* player) override { /* 已在鎖定狀態 */ }void unlock(Player* player) override;
};// ==================== 上下文方法實現 ====================
Player::Player(const std::string& name) : name_(name) {state_ = std::make_unique<ReadyState>();
}void Player::setState(std::unique_ptr<State> state) {state_ = std::move(state);
}std::string Player::getName() const {return name_;
}void Player::play() {state_->play(this);
}void Player::pause() {state_->pause(this);
}void Player::stop() {state_->stop(this);
}void Player::lock() {state_->lock(this);
}void Player::unlock() {state_->unlock(this);
}// ==================== 具體狀態方法實現 ====================
void ReadyState::play(Player* player) {std::cout << player->getName() << ": 開始播放" << std::endl;changeState(player, std::make_unique<PlayingState>());
}void ReadyState::lock(Player* player) {std::cout << player->getName() << ": 鎖定播放器" << std::endl;changeState(player, std::make_unique<LockedState>());
}void PlayingState::pause(Player* player) {std::cout << player->getName() << ": 暫停播放" << std::endl;changeState(player, std::make_unique<PausedState>());
}void PlayingState::stop(Player* player) {std::cout << player->getName() << ": 停止播放" << std::endl;changeState(player, std::make_unique<ReadyState>());
}void PlayingState::lock(Player* player) {std::cout << player->getName() << ": 鎖定播放器" << std::endl;changeState(player, std::make_unique<LockedState>());
}void PausedState::play(Player* player) {std::cout << player->getName() << ": 恢復播放" << std::endl;changeState(player, std::make_unique<PlayingState>());
}void PausedState::stop(Player* player) {std::cout << player->getName() << ": 停止播放" << std::endl;changeState(player, std::make_unique<ReadyState>());
}void PausedState::lock(Player* player) {std::cout << player->getName() << ": 鎖定播放器" << std::endl;changeState(player, std::make_unique<LockedState>());
}void LockedState::unlock(Player* player) {std::cout << player->getName() << ": 解鎖播放器" << std::endl;changeState(player, std::make_unique<ReadyState>());
}// ==================== 客戶端代碼 ====================
int main() {std::cout << "=== 狀態模式演示: 音樂播放器 ===" << std::endl;Player player("我的播放器");// 正常流程player.play();player.pause();player.play();player.stop();// 鎖定測試std::cout << "\n測試鎖定功能:" << std::endl;player.play();player.lock();player.play(); // 應該無效player.unlock();player.play();// 無效操作測試std::cout << "\n測試無效操作:" << std::endl;player.stop();player.stop(); // 應該無效player.pause(); // 應該無效return 0;
}
模式變體
1. 狀態表驅動
class StateMachine {std::unordered_map<std::string, std::unordered_map<std::string, std::function<void()>>> transitions_;std::string currentState_;public:void addTransition(const std::string& from, const std::string& event, const std::string& to, std::function<void()> action) {transitions_[from][event] = [this, to, action] {action();currentState_ = to;};}void handleEvent(const std::string& event) {auto& stateTransitions = transitions_[currentState_];if (stateTransitions.find(event) != stateTransitions.end()) {stateTransitions[event]();}}
};
2. 共享狀態對象
class SharedState : public State {// 可以共享的狀態數據
};class ConcreteStateA : public SharedState {// 實現特定行為
};// 使用時可以共享同一個狀態實例
auto sharedState = std::make_shared<ConcreteStateA>();
context1.setState(sharedState);
context2.setState(sharedState);
實際應用場景
-
工作流引擎:如訂單狀態流轉
-
游戲開發:角色行為狀態管理
-
UI系統:控件不同狀態下的行為
-
網絡協議:協議狀態機實現
-
硬件控制:設備狀態管理