狀態機淺析

狀態機是處理狀態依賴型行為的高效工具,通過結構化建模狀態轉換,解決了傳統條件判斷的冗余和混亂問題。它在設備控制、流程管理、協議解析等場景中表現優異,核心優勢在于邏輯清晰、可擴展性強和易于調試。

一、介紹

1. 概念

狀態機(State Machine)是一種用于描述對象或系統在不同狀態之間轉換規律的數學模型,它由狀態事件轉換動作四部分組成:

  • 狀態:系統在某一時刻的穩定狀況(如交通燈的“紅燈”“綠燈”)。
  • 事件:觸發狀態轉換的外部或內部信號(如“超時”“按鈕按下”)。
  • 轉換:在特定事件發生時,從一個狀態切換到另一個狀態的規則(如“紅燈超時后切換到綠燈”)。
  • 動作:狀態轉換時執行的操作(如“切換綠燈時點亮綠燈LED”)。
2. 優點
  1. 邏輯清晰
    狀態和轉換規則被顯式定義,代碼結構模塊化,便于理解和維護。例如,交通燈的狀態機可直觀列出“紅燈→超時→黃燈”等轉換,無需嵌套if-else
  2. 可擴展性強
    新增狀態或轉換規則時,只需添加新的狀態定義和轉換邏輯,無需修改現有代碼(符合開閉原則)。
  3. 易調試與測試
    狀態機的行為可通過狀態圖可視化,便于梳理所有可能的狀態轉換路徑,確保覆蓋邊界場景(如異常事件下的狀態回滾)。
  4. 降低復雜度
    將復雜的條件判斷轉化為狀態間的映射關系,減少代碼嵌套層級,尤其適合多狀態、多分支的場景(如協議解析中的狀態切換)。
  5. 標準化與復用
    狀態機模型是通用的設計模式,可通過模板(如C++的StateMachine類)封裝核心邏輯,在不同場景中復用。
3. 適應場景

狀態機適用于行為與狀態強相關狀態轉換規則明確的場景,典型包括:

  1. 設備控制
    • 交通燈(紅→黃→綠→紅的循環);
    • 電梯(待機→上行→開門→下行的狀態切換)。
  2. 流程管理
    • 訂單系統(待支付→已支付→發貨→完成);
    • 工作流審批(提交→部門審核→總經理審核→通過)。
  3. 協議解析
    • 網絡協議(TCP連接的建立→數據傳輸→斷開);
    • 串口通信(起始位→數據位→校驗位→停止位)。
  4. 游戲邏輯
    • 角色狀態( idle→行走→攻擊→受傷→死亡)。

二、狀態機類別

常見的狀態機實現方式根據抽象程度、靈活性和適用場景的不同,可分為以下幾類,各有其特點和適用范圍。以下均以交通信號燈狀態機為例,提供一個示例實現。

模擬真實交通信號燈的工作場景,可以通過輸入命令與狀態機交互:
- 輸入`e`觸發緊急情況
- 輸入`p`切換電源狀態
- 輸入`q`退出程序
1. 硬編碼狀態機(Hard-coded State Machines)

核心思想:用 if-elseswitch-case 直接硬編碼狀態轉換邏輯,是最直觀的實現方式。

#include <iostream>
#include <chrono>
#include <thread>
using namespace std;// 狀態和事件定義
enum State { RED, GREEN, YELLOW };
enum Event { TIME_OUT, EMERGENCY };State currentState = RED; // 初始狀態:紅燈// 處理事件
void processEvent(Event event) {switch (currentState) {case RED:if (event == TIME_OUT) {cout << "\n紅燈→綠燈\n";currentState = GREEN;} else if (event == EMERGENCY) {cout << "\n紅燈→黃燈(緊急)\n";currentState = YELLOW;}break;case GREEN:if (event == TIME_OUT) {cout << "\n綠燈→黃燈\n";currentState = YELLOW;} else if (event == EMERGENCY) {cout << "\n綠燈→黃燈(緊急)\n";currentState = YELLOW;}break;case YELLOW:if (event == TIME_OUT) {cout << "\n黃燈→紅燈\n";currentState = RED;} else if (event == EMERGENCY) {cout << "\n黃燈保持(緊急)\n"; // 緊急時黃燈閃爍}break;}
}// 運行紅綠燈
void run() {while (true) {int duration = 0;switch (currentState) {case RED: duration = 5; break;   // 紅燈5秒case GREEN: duration = 4; break; // 綠燈4秒case YELLOW: duration = 2; break;// 黃燈2秒}// 顯示當前狀態并等待cout << (currentState == RED ? "紅燈" : currentState == GREEN ? "綠燈" : "黃燈") << "亮(" << duration << "秒)";for (int i = 0; i < duration; ++i) {cout << "."; cout.flush();this_thread::sleep_for(chrono::seconds(1));}// 定時結束,觸發事件processEvent(TIME_OUT);}
}int main() {thread t(run);t.detach();// 模擬緊急事件輸入string input;while (cin >> input) {if (input == "e") processEvent(EMERGENCY);}return 0;
}
特點:
  • 優點:實現簡單,無需額外框架,適合狀態少、轉換規則簡單的場景(如簡易設備控制)。
  • 缺點:狀態或事件增多時,代碼臃腫(嵌套層級深)、維護困難(修改一處可能影響多處)。
  • 適用場景:嵌入式小設備、簡單流程(如LED閃爍控制)。
2. 狀態表驅動的狀態機(State Table-driven Machines)
實現

核心思想:用表格(數組/字典) 存儲“狀態-事件-動作-下一狀態”的映射關系,通過遍歷表格處理狀態轉換(本文之前示例均為此方式)。

#include <iostream>
#include <string>
#include <chrono>
#include <thread>// 1. 定義事件類型
enum TrafficEvent {TIME_OUT,       // 定時結束事件EMERGENCY,      // 緊急情況事件POWER_OFF,      // 斷電事件POWER_ON,       // 上電事件NONE            // 無事件(終止符)
};// 2. 前向聲明狀態數組
extern const class TrafficState RedLight[];
extern const class TrafficState GreenLight[];
extern const class TrafficState YellowLight[];
extern const class TrafficState OffState[];// 3. 狀態機類(交通信號燈控制器)
class TrafficLightController {
public:// 狀態處理函數的參數類型struct Param {int duration;       // 持續時間(秒)std::string reason; // 事件原因描述};// 構造函數:初始化狀態為關閉TrafficLightController() : currentState(OffState) {}// 獲取當前狀態名稱std::string getCurrentStateName() const;// 處理事件并轉換狀態void handleEvent(TrafficEvent event, const Param& param);// 運行狀態機(自動計時切換)void run();// 緊急情況處理void triggerEmergency() {Param param{0, "手動觸發緊急模式"};handleEvent(EMERGENCY, param);}// 電源控制void powerToggle() {Param param{0, ""};if (currentState == OffState) {param.reason = "電源開啟";handleEvent(POWER_ON, param);} else {param.reason = "電源關閉";handleEvent(POWER_OFF, param);}}// 靜態處理函數(用于狀態表,避免lambda轉換問題)static void redToGreenHandler(const Param& param) {handleGreenLightOn(param);}static void redEmergencyHandler(const Param& param) {handleEmergency(param);}static void redPowerOffHandler(const Param& param) {handleLightOff(param);}static void greenToYellowHandler(const Param& param) {handleYellowLightOn(param);}static void greenEmergencyHandler(const Param& param) {handleEmergency(param);}static void greenPowerOffHandler(const Param& param) {handleLightOff(param);}static void yellowToRedHandler(const Param& param) {handleRedLightOn(param);}static void yellowEmergencyHandler(const Param& param) {handleEmergency(param);}static void yellowPowerOffHandler(const Param& param) {handleLightOff(param);}static void offToRedHandler(const Param& param) {handleRedLightOn(param);}private:const TrafficState* currentState; // 當前狀態// 狀態處理函數實現(交通信號燈的具體行為)static void handleRedLightOn(const Param& param) {std::cout << "\n[紅燈亮] 禁止通行,持續 " << param.duration << " 秒 " << (param.reason.empty() ? "" : "(" + param.reason + ")") << std::endl;}static void handleGreenLightOn(const Param& param) {std::cout << "\n[綠燈亮] 可以通行,持續 " << param.duration << " 秒 "<< (param.reason.empty() ? "" : "(" + param.reason + ")") << std::endl;}static void handleYellowLightOn(const Param& param) {std::cout << "\n[黃燈亮] 準備停止,持續 " << param.duration << " 秒 "<< (param.reason.empty() ? "" : "(" + param.reason + ")") << std::endl;}static void handleLightOff(const Param& param) {std::cout << "\n[燈關閉] 所有燈光關閉 "<< (param.reason.empty() ? "" : "(" + param.reason + ")") << std::endl;}static void handleEmergency(const Param& param) {std::cout << "\n[緊急模式] 所有燈光閃爍 "<< (param.reason.empty() ? "" : "(" + param.reason + ")") << std::endl;}
};// 4. 狀態結構體定義(狀態表的核心)
class TrafficState {
public:TrafficEvent event;                  // 觸發事件const TrafficState* nextState;       // 事件發生后轉移到的狀態void (*handler)(const TrafficLightController::Param&); // 改為靜態函數指針const char* stateName;               // 狀態名稱(用于打印)
};// 5. 狀態轉移表定義(核心邏輯)
// 紅燈狀態的轉移規則
const TrafficState RedLight[] = {{TIME_OUT,    GreenLight,  &TrafficLightController::redToGreenHandler,   "紅燈"},{EMERGENCY,   YellowLight, &TrafficLightController::redEmergencyHandler, "紅燈"},{POWER_OFF,   OffState,    &TrafficLightController::redPowerOffHandler,  "紅燈"},{NONE,        nullptr,     nullptr,                                      nullptr}
};// 綠燈狀態的轉移規則
const TrafficState GreenLight[] = {{TIME_OUT,    YellowLight, &TrafficLightController::greenToYellowHandler,  "綠燈"},{EMERGENCY,   YellowLight, &TrafficLightController::greenEmergencyHandler, "綠燈"},{POWER_OFF,   OffState,    &TrafficLightController::greenPowerOffHandler,  "綠燈"},{NONE,        nullptr,     nullptr,                                       nullptr}
};// 黃燈狀態的轉移規則
const TrafficState YellowLight[] = {{TIME_OUT,    RedLight,    &TrafficLightController::yellowToRedHandler,    "黃燈"},{EMERGENCY,   YellowLight, &TrafficLightController::yellowEmergencyHandler, "黃燈"},{POWER_OFF,   OffState,    &TrafficLightController::yellowPowerOffHandler,  "黃燈"},{NONE,        nullptr,     nullptr,                                        nullptr}
};// 關閉狀態的轉移規則
const TrafficState OffState[] = {{POWER_ON,    RedLight,    &TrafficLightController::offToRedHandler,    "關閉"},{NONE,        nullptr,     nullptr,                                    nullptr}
};// 6. 狀態機類成員函數實現
std::string TrafficLightController::getCurrentStateName() const {return currentState->stateName;
}void TrafficLightController::handleEvent(TrafficEvent event, const Param& param) {// 遍歷當前狀態的轉移表,查找匹配的事件for (int i = 0; ; i++) {const TrafficState& entry = currentState[i];if (entry.event == NONE) {// 未找到匹配的事件處理規則std::cout << "[警告] 狀態 " << currentState->stateName << " 不處理事件類型 " << event << std::endl;return;}if (entry.event == event) {// 調用事件處理函數entry.handler(param);// 狀態轉移const TrafficState* prevState = currentState;currentState = entry.nextState;std::cout << "[狀態切換] 從 " << prevState->stateName << " 切換到 " << currentState->stateName << std::endl;return;}}
}void TrafficLightController::run() {std::cout << "交通信號燈系統啟動..." << std::endl;while (true) {// 根據當前狀態設置不同的定時時間int duration = 0;if (currentState == RedLight) {duration = 10; // 紅燈持續10秒} else if (currentState == GreenLight) {duration = 8;  // 綠燈持續8秒} else if (currentState == YellowLight) {duration = 3;  // 黃燈持續3秒} else if (currentState == OffState) {// 如果是關閉狀態,等待1秒后再次檢查std::this_thread::sleep_for(std::chrono::seconds(1));continue;}// 等待定時結束for (int i = 0; i < duration; i++) {std::cout << ".";std::cout.flush();std::this_thread::sleep_for(std::chrono::seconds(1));}// 定時結束,觸發狀態切換事件Param param{duration, "定時結束"};handleEvent(TIME_OUT, param);}
}// 7. 演示程序
int main() {TrafficLightController controller;// 上電(從關閉狀態切換到紅燈)controller.powerToggle();// 啟動狀態機自動運行std::thread runner(&TrafficLightController::run, &controller);runner.detach();// 模擬用戶輸入控制std::string input;while (true) {std::cout << "\n輸入命令 (e:緊急情況, p:電源開關, q:退出): ";std::cin >> input;if (input == "e") {controller.triggerEmergency();} else if (input == "p") {controller.powerToggle();} else if (input == "q") {std::cout << "程序退出" << std::endl;break;} else {std::cout << "未知命令,請重新輸入" << std::endl;}}return 0;
}
1. 核心組成部分
  • 狀態定義:紅燈(RedLight)、綠燈(GreenLight)、黃燈(YellowLight)、關閉(OffState)四種狀態
  • 事件類型:定時結束(TIME_OUT)、緊急情況(EMERGENCY)、電源開關(POWER_ON/POWER_OFF)
  • 狀態轉移表:每個狀態都定義了對不同事件的響應規則和目標狀態
  • 處理函數:每種狀態切換都有對應的行為(如燈光提示、持續時間顯示)
2. 狀態機工作流程
  1. 系統啟動后處于關閉狀態,上電后切換到紅燈
  2. 紅燈持續10秒后自動切換到綠燈(TIME_OUT事件)
  3. 綠燈持續8秒后自動切換到黃燈(TIME_OUT事件)
  4. 黃燈持續3秒后自動切換到紅燈(TIME_OUT事件)
  5. 遇到緊急情況時,所有狀態都切換到黃燈閃爍模式
  6. 支持電源開關控制,可隨時關閉或開啟信號燈
3. 狀態表驅動的優勢
  • 邏輯清晰:狀態轉換規則集中定義在狀態表中,一目了然
  • 易于擴展:新增狀態或事件只需修改狀態表,無需改動核心邏輯
  • 可維護性高:狀態和行為分離,修改狀態轉換或行為都很方便
  • 可測試性好:可以通過發送特定事件來測試狀態機的響應
優化
優化點
  1. 模板化狀態機框架

    • 定義 StateMachine<T, P> 模板類:通過 current 指針指向當前狀態,遍歷狀態表(p->nextState != nullptr 作為終止條件),匹配事件后執行動作并切換狀態。
    • 模板參數 T 為狀態機所屬的目標類(如 TrafficLightController),P 為事件參數類型,實現通用化復用。
  2. 狀態管理邏輯

    • 狀態結構體 State<T, P> 包含 inputEvent(事件)、action(處理函數)、nextState(下一個狀態)、errorState(錯誤狀態)。
    • 通過 currentState() 接口獲取當前狀態。
  3. 事件處理流程

    • ProcessEvent 函數邏輯:遍歷當前狀態表(for (State* p = current; p->nextState != NULL; p++)),匹配事件后執行 action,再切換到 nextState
    • 支持錯誤狀態處理(errorState),可在動作執行失敗時切換(示例中簡化處理,實際可擴展為返回執行結果判斷)。
  4. 低耦合與可擴展性

    • 具體業務邏輯(如交通信號燈的狀態名稱、定時時間、動作實現)封裝在 TrafficLightController 中,與通用狀態機框架解耦。
    • 新增狀態或事件時,只需擴展狀態轉移表(如添加 FlashingState 閃爍狀態),無需修改 StateMachine 核心邏輯。
#include <iostream>
#include <string>
#include <chrono>
#include <thread>// 1. 提前聲明參數結構體和控制器類
struct TrafficParam;
class TrafficLightController;// 2. 通用狀態結構體(模板化)
template <class T, class P>
struct State {int inputEvent;               // 輸入事件void (T::*action)(int, const P&); // 事件處理動作State<T, P>* nextState;       // 正常下一個狀態State<T, P>* errorState;      // 錯誤狀態
};// 3. 通用狀態機模板類
template <class T, class P>
class StateMachine {
public:// 構造函數:綁定目標對象和初始狀態StateMachine(T* target, State<T, P>* initialState) : target(target), current(initialState) {}// 事件處理核心函數void ProcessEvent(int event, const P& param) {for (State<T, P>* p = current; p->nextState != nullptr; p++) {if (p->inputEvent == event) {if (p->action != nullptr) {(target->*(p->action))(event, param);}current = p->nextState;return;}}std::cout << "[警告] 未處理事件: " << event << std::endl;}// 獲取當前狀態State<T, P>* currentState() const {return current;}protected:T* target;               // 目標對象State<T, P>* current;    // 當前狀態
};// 4. 定義參數結構體(在控制器類外部,解決不完全類型問題)
struct TrafficParam {int duration;       // 持續時間(秒)std::string reason; // 事件描述
};// 5. 交通信號燈控制器(繼承通用狀態機)
class TrafficLightController : public StateMachine<TrafficLightController, TrafficParam> {
public:// 事件類型(用整數表示)enum Event {TIME_OUT = 1,EMERGENCY = 2,POWER_OFF = 3,POWER_ON = 4,NONE = 0};// 構造函數:初始化狀態機TrafficLightController() : StateMachine<TrafficLightController, TrafficParam>(this, &OffState[0]) {}// 啟動狀態機void run() {std::cout << "交通信號燈系統啟動...\n" << std::endl;while (true) {int duration = 0;// 訪問基類的currentState()方法if (StateMachine::currentState() == &RedState[0]) duration = 5;else if (StateMachine::currentState() == &GreenState[0]) duration = 4;else if (StateMachine::currentState() == &YellowState[0]) duration = 2;else if (StateMachine::currentState() == &OffState[0]) {std::this_thread::sleep_for(std::chrono::seconds(1));continue;}// 等待定時結束std::cout << getStateName(StateMachine::currentState()) << "亮(" << duration << "秒)";for (int i = 0; i < duration; ++i) {std::cout << ".";std::cout.flush();std::this_thread::sleep_for(std::chrono::seconds(1));}std::cout << std::endl;// 觸發定時結束事件TrafficParam param{duration, "定時結束"};StateMachine::ProcessEvent(TIME_OUT, param);}}// 觸發緊急情況void triggerEmergency() {TrafficParam param{0, "手動緊急觸發"};StateMachine::ProcessEvent(EMERGENCY, param);}// 切換電源void powerToggle() {TrafficParam param{0, ""};if (StateMachine::currentState() == &OffState[0]) {param.reason = "電源開啟";StateMachine::ProcessEvent(POWER_ON, param);} else {param.reason = "電源關閉";StateMachine::ProcessEvent(POWER_OFF, param);}}// 狀態名稱映射std::string getStateName(State<TrafficLightController, TrafficParam>* state) {if (state == &RedState[0]) return "紅燈";if (state == &GreenState[0]) return "綠燈";if (state == &YellowState[0]) return "黃燈";if (state == &OffState[0]) return "關閉";return "未知狀態";}// 事件處理動作(成員函數)void onRedToGreen(int event, const TrafficParam& param) {std::cout << "[動作] 紅燈→綠燈," << param.reason << std::endl;}void onGreenToYellow(int event, const TrafficParam& param) {std::cout << "[動作] 綠燈→黃燈," << param.reason << std::endl;}void onYellowToRed(int event, const TrafficParam& param) {std::cout << "[動作] 黃燈→紅燈," << param.reason << std::endl;}void onEmergency(int event, const TrafficParam& param) {std::cout << "[動作] 觸發緊急模式," << param.reason << std::endl;}void onPowerOff(int event, const TrafficParam& param) {std::cout << "[動作] 電源關閉," << param.reason << std::endl;}void onPowerOn(int event, const TrafficParam& param) {std::cout << "[動作] 電源開啟," << param.reason << std::endl;}// 狀態轉移表(靜態成員)static State<TrafficLightController, TrafficParam> RedState[];static State<TrafficLightController, TrafficParam> GreenState[];static State<TrafficLightController, TrafficParam> YellowState[];static State<TrafficLightController, TrafficParam> OffState[];
};// 6. 初始化狀態轉移表
State<TrafficLightController, TrafficParam> TrafficLightController::RedState[] = {{TIME_OUT,   &TrafficLightController::onRedToGreen, GreenState, nullptr},{EMERGENCY,  &TrafficLightController::onEmergency,  YellowState, nullptr},{POWER_OFF,  &TrafficLightController::onPowerOff,   OffState, nullptr},{NONE,       nullptr,                               nullptr, nullptr}
};State<TrafficLightController, TrafficParam> TrafficLightController::GreenState[] = {{TIME_OUT,   &TrafficLightController::onGreenToYellow, YellowState, nullptr},{EMERGENCY,  &TrafficLightController::onEmergency,     YellowState, nullptr},{POWER_OFF,  &TrafficLightController::onPowerOff,      OffState, nullptr},{NONE,       nullptr,                                  nullptr, nullptr}
};State<TrafficLightController, TrafficParam> TrafficLightController::YellowState[] = {{TIME_OUT,   &TrafficLightController::onYellowToRed, RedState, nullptr},{EMERGENCY,  &TrafficLightController::onEmergency,   YellowState, nullptr},{POWER_OFF,  &TrafficLightController::onPowerOff,    OffState, nullptr},{NONE,       nullptr,                                nullptr, nullptr}
};State<TrafficLightController, TrafficParam> TrafficLightController::OffState[] = {{POWER_ON,   &TrafficLightController::onPowerOn, RedState, nullptr},{NONE,       nullptr,                            nullptr, nullptr}
};// 7. 主函數
int main() {TrafficLightController controller;controller.powerToggle(); // 上電// 啟動自動運行線程std::thread runner(&TrafficLightController::run, &controller);runner.detach();// 用戶交互std::string input;while (true) {std::cout << "\n輸入命令 (e:緊急情況, p:電源開關, q:退出): ";std::cin >> input;if (input == "e") {controller.triggerEmergency();} else if (input == "p") {controller.powerToggle();} else if (input == "q") {std::cout << "程序退出" << std::endl;return 0;} else {std::cout << "未知命令,請重新輸入" << std::endl;}}
}
編譯與運行
g++ -std=c++11 main.cpp -o main -lpthread
./main
3. 面向對象狀態機(Object-oriented State Machines)

核心思想:將每個狀態封裝為獨立的類,通過多態實現狀態轉換,符合面向對象的“單一職責原則”。:

#include <iostream>
#include <chrono>
#include <thread>
using namespace std;// 前向聲明
class TrafficLight;// 狀態基類
class State {
public:virtual string getName() = 0;          // 獲取狀態名稱virtual int getDuration() = 0;         // 獲取持續時間virtual void onTimeout(TrafficLight* tl) = 0; // 處理超時事件virtual void onEmergency(TrafficLight* tl) = 0; // 處理緊急事件virtual ~State() = default;
};// 紅綠燈控制器
class TrafficLight {
public:// 狀態實例(單例)class RedState : public State {public:string getName() override { return "紅燈"; }int getDuration() override { return 5; }void onTimeout(TrafficLight* tl) override;void onEmergency(TrafficLight* tl) override;};class GreenState : public State {public:string getName() override { return "綠燈"; }int getDuration() override { return 4; }void onTimeout(TrafficLight* tl) override;void onEmergency(TrafficLight* tl) override;};class YellowState : public State {public:string getName() override { return "黃燈"; }int getDuration() override { return 2; }void onTimeout(TrafficLight* tl) override;void onEmergency(TrafficLight* tl) override;};// 初始化狀態為紅燈TrafficLight() : currentState(&redState) {}// 處理事件void triggerTimeout() { currentState->onTimeout(this); }void triggerEmergency() { currentState->onEmergency(this); }// 切換狀態void setState(State* state) { currentState = state; }// 獲取狀態實例(供狀態類調用)RedState* getRedState() { return &redState; }GreenState* getGreenState() { return &greenState; }YellowState* getYellowState() { return &yellowState; }// 運行void run() {while (true) {string name = currentState->getName();int duration = currentState->getDuration();cout << name << "亮(" << duration << "秒)";for (int i = 0; i < duration; ++i) {cout << "."; cout.flush();this_thread::sleep_for(chrono::seconds(1));}triggerTimeout(); // 超時事件}}private:RedState redState;GreenState greenState;YellowState yellowState;State* currentState;
};// 實現狀態轉換邏輯
void TrafficLight::RedState::onTimeout(TrafficLight* tl) {cout << "\n[轉換] 紅燈→綠燈\n";tl->setState(tl->getGreenState());
}
void TrafficLight::RedState::onEmergency(TrafficLight* tl) {cout << "\n[轉換] 紅燈→黃燈(緊急)\n";tl->setState(tl->getYellowState());
}void TrafficLight::GreenState::onTimeout(TrafficLight* tl) {cout << "\n[轉換] 綠燈→黃燈\n";tl->setState(tl->getYellowState());
}
void TrafficLight::GreenState::onEmergency(TrafficLight* tl) {cout << "\n[轉換] 綠燈→黃燈(緊急)\n";tl->setState(tl->getYellowState());
}void TrafficLight::YellowState::onTimeout(TrafficLight* tl) {cout << "\n[轉換] 黃燈→紅燈\n";tl->setState(tl->getRedState());
}
void TrafficLight::YellowState::onEmergency(TrafficLight* tl) {cout << "\n[轉換] 黃燈保持(緊急)\n";
}int main() {TrafficLight light;thread t(&TrafficLight::run, &light);t.detach();// 模擬緊急事件string input;while (cin >> input) {if (input == "e") light.triggerEmergency();}return 0;
}

特點

  • 優點:狀態邏輯完全封裝在類中,修改一個狀態不影響其他狀態,可擴展性極強(新增狀態只需新增類)。
  • 缺點:類數量多(每個狀態一個類),實現較繁瑣,適合復雜場景。
  • 適用場景:復雜狀態機(如游戲角色狀態、工業設備控制邏輯)。
4. 框架/庫實現的狀態機(Framework-based State Machines)

核心思想:使用成熟的狀態機庫(如 Boost.Statechart、Qt State Machine Framework),通過配置或 DSL(領域特定語言)定義狀態機,無需重復開發基礎邏輯。

// Boost.Statechart 偽代碼:
#include <iostream>
#include <chrono>
#include <thread>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/transition.hpp>namespace sc = boost::statechart;// 事件定義
struct EvTimeout : sc::event<EvTimeout> {};       // 定時結束
struct EvEmergency : sc::event<EvEmergency> {};   // 緊急情況// 狀態機:紅綠燈系統
struct TrafficLight : sc::state_machine<TrafficLight, struct RedState> {};// 紅燈狀態
struct RedState : sc::simple_state<RedState, TrafficLight> {RedState() { cout << "\n進入紅燈狀態(5秒)\n"; }// 轉換規則:超時→綠燈,緊急→黃燈typedef sc::transition<EvTimeout, struct GreenState> +sc::transition<EvEmergency, struct YellowState> reactions;
};// 綠燈狀態
struct GreenState : sc::simple_state<GreenState, TrafficLight> {GreenState() { cout << "\n進入綠燈狀態(4秒)\n"; }// 轉換規則:超時→黃燈,緊急→黃燈typedef sc::transition<EvTimeout, struct YellowState> +sc::transition<EvEmergency, struct YellowState> reactions;
};// 黃燈狀態
struct YellowState : sc::simple_state<YellowState, TrafficLight> {YellowState() { cout << "\n進入黃燈狀態(2秒)\n"; }// 轉換規則:超時→紅燈,緊急→自身(保持)typedef sc::transition<EvTimeout, RedState> +sc::transition<EvEmergency, YellowState> reactions;
};// 運行狀態機
void run(TrafficLight& light) {while (true) {// 根據當前狀態設置定時int duration = 0;if (light.state_cast<RedState*>() != nullptr) duration = 5;else if (light.state_cast<GreenState*>() != nullptr) duration = 4;else if (light.state_cast<YellowState*>() != nullptr) duration = 2;// 等待定時for (int i = 0; i < duration; ++i) {cout << "."; cout.flush();std::this_thread::sleep_for(std::chrono::seconds(1));}light.process_event(EvTimeout()); // 觸發超時事件}
}int main() {TrafficLight light;light.initiate(); // 啟動狀態機(初始為紅燈)// 啟動運行線程std::thread t(run, std::ref(light));t.detach();// 處理緊急事件輸入std::string input;while (std::cin >> input) {if (input == "e") light.process_event(EvEmergency());}return 0;
}

特點

  • 優點:庫已封裝狀態管理、事件分發等復雜邏輯,支持嵌套狀態、并行狀態等高級特性,可靠性高。
  • 缺點:依賴第三方庫,學習成本較高,可能引入不必要的復雜性(簡單場景用不上)。
  • 適用場景:大型項目或需要高級特性(如并行狀態、歷史狀態)的場景(如車載系統、工業控制軟件)。
5. 有限狀態機(FSM)工具生成的狀態機

核心思想:通過可視化工具(如 Stateflow、Enterprise Architect)繪制狀態圖,自動生成代碼(C/C++/Python 等),避免手動編碼錯誤。
特點

  • 優點:可視化設計狀態轉換,自動生成規范代碼,適合團隊協作和復雜狀態邏輯(如狀態嵌套、并行分支)。
  • 缺點:依賴工具,生成的代碼可能冗余,修改需通過工具重新生成。
  • 適用場景:大規模嵌入式系統、汽車電子(如自動駕駛狀態邏輯)。
    面向對象狀態機與設計模式中的狀態模式(State Pattern) 既有聯系又有區別,核心差異體現在范圍、實現方式和設計目標上。下面詳細解析兩者的關系與區別:

三、狀態機與狀態模式的異同

1. 概念定義
  • 面向對象狀態機(Object-Oriented State Machine)
    用面向對象(OOP)思想和技術實現的狀態機,其核心是通過類、對象、繼承、多態等OOP特性,將狀態機的“狀態”“事件”“轉換規則”“行為”等元素封裝為對象,以實現狀態的管理和轉換。
    它是一個寬泛的概念,只要符合“用OOP思想實現狀態機”的邏輯,都可稱為面向對象狀態機。
  • 狀態模式(State Pattern)
    是GoF(四人組)定義的23種設計模式之一(行為型模式),其核心思想是將對象的狀態封裝為獨立的狀態類,使對象在不同狀態下的行為由對應的狀態類處理,從而避免大量的條件判斷(如if-elseswitch-case)。
    它是一種具體的設計模式,有明確的結構規范(環境類、抽象狀態類、具體狀態類)。
2. 相同點

狀態模式本質上是面向對象狀態機的典型實現方式
狀態模式通過OOP的“封裝”和“多態”特性,將狀態的行為與轉換邏輯封裝到獨立的狀態類中,完全符合“面向對象狀態機”的設計思想。因此,用狀態模式實現的狀態機,一定是面向對象狀態機

3. 差異點
維度面向對象狀態機狀態模式(State Pattern)
范圍寬泛概念:所有用OOP實現的狀態機都屬于此類具體模式:是面向對象狀態機的一種特定實現
結構規范無固定結構,可靈活設計有嚴格結構:環境類(Context)+ 抽象狀態類(State)+ 具體狀態類(ConcreteState)
核心目標用OOP管理狀態機的元素(狀態、事件、轉換)消除狀態相關的條件判斷,讓狀態行為更易維護
靈活性可簡單可復雜(如用枚舉+switch也屬于OOP實現)必須通過狀態類封裝行為,靈活性更高(符合開閉原則)
適用場景狀態較少、轉換邏輯簡單時可簡化實現狀態較多、行為復雜、頻繁新增/修改狀態時更適用
4. 具體差異示例(以紅綠燈為例)
1. 非狀態模式的面向對象狀態機(仍屬OOP實現)

用枚舉定義狀態,在環境類中通過switch-case處理狀態轉換(未用狀態模式,但符合OOP思想):

// 枚舉定義狀態(OOP中的封裝)
enum class TrafficLightState { RED, GREEN, YELLOW };class TrafficLight {
private:TrafficLightState currentState; // 狀態作為對象成員(OOP特性)
public:TrafficLight() : currentState(TrafficLightState::RED) {}void nextState() {// 用switch處理狀態轉換(未用狀態模式)switch (currentState) {case TrafficLightState::RED:currentState = TrafficLightState::GREEN;std::cout << "切換為綠燈\n";break;case TrafficLightState::GREEN:currentState = TrafficLightState::YELLOW;std::cout << "切換為黃燈\n";break;case TrafficLightState::YELLOW:currentState = TrafficLightState::RED;std::cout << "切換為紅燈\n";break;}}
};
  • 這是面向對象狀態機(用類、對象管理狀態),但未使用狀態模式(依賴switch判斷狀態)。
2. 狀態模式實現的面向對象狀態機

嚴格遵循狀態模式結構,將狀態行為封裝到獨立的狀態類中:

// 抽象狀態類(State)
class LightState {
public:virtual void nextState(TrafficLight* light) = 0; // 多態接口virtual ~LightState() = default;
};// 具體狀態類:紅燈
class RedState : public LightState {
public:void nextState(TrafficLight* light) override {light->setState(new GreenState()); // 轉換為綠燈std::cout << "切換為綠燈\n";}
};// 具體狀態類:綠燈、黃燈(類似RedState,略)// 環境類(Context)
class TrafficLight {
private:LightState* currentState; // 依賴抽象狀態
public:TrafficLight() : currentState(new RedState()) {}void setState(LightState* state) {delete currentState;currentState = state;}void nextState() {currentState->nextState(this); // 委托給狀態類處理}
};
  • 這是狀態模式,同時也是面向對象狀態機(用OOP的繼承、多態實現)。
5. 總結
  • 狀態模式是面向對象狀態機的“子集”:狀態模式是一種規范的、高靈活性的面向對象狀態機實現方式。
  • 核心區別:面向對象狀態機是“用OOP實現狀態機”的統稱,可簡單可復雜;而狀態模式是一種嚴格結構化的設計模式,專為解決“狀態行為復雜、需避免條件判斷”的問題而生。狀態少、邏輯簡單時,可用簡單的面向對象狀態機(如枚舉+switch);狀態多、行為復雜時,優先用狀態模式(更易擴展和維護)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95086.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95086.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95086.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Windows 手動病毒排查指南:不依賴殺毒軟件的系統安全防護

Windows 手動病毒排查指南&#xff1a;不依賴殺毒軟件的系統安全防護 在數字時代&#xff0c;電腦病毒就像潛伏的"網絡幽靈"&#xff0c;從竊取隱私的木馬到消耗資源的蠕蟲&#xff0c;時刻威脅著系統安全。當殺毒軟件失效或遭遇新型威脅時&#xff0c;手動排查病毒便…

GPT-5 is here

GPT-5 is here https://openai.com/index/introducing-gpt-5/ — and it’s #1 across the board! #1 in Text, WebDev, and Vision Arena #1 in Hard Prompts, Coding, Math, Creativity, Long Queries, and more Tested under the codename “summit”, GPT-5 now holds the …

【華為機試】55. 跳躍游戲

文章目錄55. 跳躍游戲題目描述示例 1&#xff1a;示例 2&#xff1a;提示&#xff1a;解題思路一、問題本質與建模二、方法總覽與選擇三、貪心算法的正確性&#xff08;直觀解釋 循環不變式&#xff09;四、反向貪心&#xff1a;等價但有啟發的視角五、與動態規劃的對比與誤區…

RabbitMQ面試精講 Day 18:內存與磁盤優化配置

【RabbitMQ面試精講 Day 18】內存與磁盤優化配置 開篇&#xff1a;內存與磁盤優化的重要性 歡迎來到"RabbitMQ面試精講"系列的第18天&#xff01;今天我們將深入探討RabbitMQ的內存與磁盤優化配置&#xff0c;這是面試中經常被問及的高頻主題&#xff0c;也是生產環…

【C++】string 的特性和使用

Ciallo&#xff5e; (∠?ω< )⌒★ string&#xff08;1&#xff09;1. 構造函數1.1 string();1.2 string(const char* s);1.3 string(const string& str);1.4 string(size_t n, char c);1.5 string(const string& str, size_t pos, size_t len npos);1.6 string(…

創始人IP的精神修煉:于成長中積蓄力量

IP 經濟席卷之下&#xff0c;眾多企業家常被 “是否入局 IP”“能否做好 IP” 的焦慮裹挾。這種潛藏的精神內耗&#xff0c;對企業根基的侵蝕往往勝過業績的起伏。著名文化學者于丹在全球創始人 IP 領袖高峰論壇上的洞見&#xff0c;為創始人 IP 的精神成長照亮了前路&#xff…

gbase8s數據庫中對象元數據查詢

最近整理了gbase8s數據庫中常見的元數據的查詢&#xff0c;包括表、視圖、序列、包、類型、觸發器、plsql等等&#xff0c;僅供參考。set environment sqlmode oracle; drop package DBMS_METADATA; create or replace package DBMS_METADATA is function GET_DDL(objtype varc…

常用hook鉤子函數

爬蟲Hook技術常用字段和勾子函數 目錄 Hook技術概述網絡請求相關Hook瀏覽器環境HookJavaScript引擎Hook加密算法Hook反爬蟲檢測Hook實際應用示例Hook工具和框架 Hook技術概述 Hook&#xff08;鉤子&#xff09;技術是一種在程序運行時攔截和修改函數調用的技術。在爬蟲中&a…

【解決方法】華為電腦的亮度調節失靈

華為電腦的亮度調節失靈 參考文章&#xff1a; 華為電腦屏幕亮度怎么調不了&#xff1f;華為電腦調節亮度沒反應解決教程 親測&#xff0c;在控制面板中卸載HWOSD&#xff0c;再重裝有用。

【軟考中級網絡工程師】知識點之 DCC 深度剖析

目錄一、DCC 是什么1.1 定義闡述1.2 作用講解二、DCC 工作原理2.1 撥號觸發機制2.1.1 感興趣流量定義2.1.2 觸發撥號過程2.2 鏈路建立流程2.2.1 物理鏈路連接2.2.2 數據鏈路層協議協商三、DCC 配置要點3.1 基礎配置步驟3.1.1 接口配置3.1.2 撥號映射配置3.2 高級配置參數3.2.1 …

W5500之Socket寄存器區介紹

W5500之Socket寄存器區介紹1)、Socket n模式寄存器(Socket n Mode Register&#xff0c;簡寫Sn_MR)偏移地址為0x0000&#xff0c;可讀寫&#xff0c;復位值為0x00&#xff1b;Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0MULTI/MFENBCASTBND/MC/MMBUCASTB/MIP6BP3P2P1P0MULTI/MFEN占用“S…

酉矩陣(Unitary Matrix)和隨機矩陣

先討論酉矩陣&#xff08;Unitary Matrix&#xff09;的性質。1. 酉矩陣定義酉矩陣&#xff08;Unitary Matrix&#xff09;是復數域上的方陣&#xff0c;滿足以下條件&#xff1a;其中&#xff1a;是 的共軛轉置&#xff08;即 Hermitian 轉置&#xff0c; &#xff09;。是單…

「iOS」————單例與代理

iOS學習單例代理代理模式的原理代理的循環引用設計模式單例 優點&#xff1a; 全局訪問&#xff1a;單例模式確保一個類只有一個實例&#xff0c;并提供全局訪問點&#xff0c;方便在整個應用中共享數據或功能。節省資源&#xff1a;由于只創建一個實例&#xff0c;可以減少內…

Microsoft Dynamics AX 性能優化解決方案

一、方案背景Microsoft Dynamics AX 是功能強大的企業ERP系統&#xff0c;雖然Microsoft 已推出基于云的現代化 ERP 平臺 Dynamics 365 Finance and Operations&#xff0c;提供了更高的性能和持續更新&#xff0c;用來替代Dynamics AX。在考慮升級到Dynamics 365之前&#xff…

ARM保留的標準中斷處理程序入口和外設中斷處理程序入口介紹

在ARM架構中&#xff0c;中斷處理是一個關鍵機制&#xff0c;它允許CPU在執行主程序時能夠響應外部或內部的事件。對于ARM MCU&#xff08;微控制器單元&#xff09;而言&#xff0c;中斷處理程序入口通常分為兩類&#xff1a;ARM保留的標準中斷處理程序入口和外設中斷處理程序…

防火墻環境下的全網服務器數據自動化備份平臺搭建:基于 rsync 的完整實施指南

一、項目總覽 1.內容介紹 本文以 3 臺 CentOS 7.9 服務器&#xff08;Web 服務器、NFS 服務器、備份服務器&#xff09;為載體&#xff0c;詳解如何在全防火墻開啟的前提下&#xff0c;搭建一套自動化數據備份平臺&#xff1a;每日自動打包 Web 站點、NFS 共享數據及系統關鍵…

Spring之【Import】

目錄 Import注解 源碼分析 使用示例 ImportSelector 源碼分析 使用示例 DeferredImportSelector 源碼分析 使用示例 ImportBeanDefinitionRegistrar 源碼分析 使用示例 Import注解 源碼分析 處理組件類上的Import注解 將Import引入類對應的BeanDefinition對象添加…

RN項目環境搭建和使用-Mac版本(模擬器啟動不起來的排查)

ReactNative&#xff1a; https://github.com/facebook/react-native https://reactnative.cn/docs/getting-started &#xff08;可以先通讀一下這個&#xff09; 環境搭建 &#xff08;mac版&#xff09;https://juejin.cn/post/7404860612758765605 搭建之前確認版本&#x…

懸賞任務系統網站兼職賺錢小程序搭建地推抖音視頻任務拉新源碼功能詳解二開

功能詳解&#xff08;一&#xff09;登錄與注冊1、登錄&#xff1a;打開系統用戶端&#xff0c;輸入已注冊的手機號&#xff0c;若為首次登錄或忘記密碼&#xff0c;可通過 “找回密碼” 功能&#xff0c;按提示驗證身份后重置密碼登錄。 2、注冊&#xff1a;點擊 “注冊” 按鈕…

scikit-learn/sklearn學習|線性回歸解讀

【1】引言 前序學習進程中&#xff0c;對SVM相關的數學原理進行了探索和推導&#xff0c;相關文章鏈接包括且不限于&#xff1a; python學智能算法&#xff08;二十六&#xff09;|SVM-拉格朗日函數構造-CSDN博客 python學智能算法&#xff08;二十八&#xff09;|SVM-拉格朗…