行為型模式關注對象之間的通訊與職責分配。本文一次呈現 7 種經典行為型模式的 C++ 實現:Iterator、Template Method、Strategy、State、Observer、Command、Memento,每種模式均附帶 UML 說明、核心代碼與 Main.cpp 測試案例,適合快速查閱與實戰參考。
意圖:封裝聚合對象內部結構,提供統一遍歷介面,不暴露內部表示。
// PlayerManager 內嵌 Iterator 類別
struct Iterator {
Iterator(std::vector<Player*>* ref) : mref(ref), mIndex(0) {}
Player* operator*() { return (*mref)[mIndex]; }
Iterator& operator++() { ++mIndex; return *this; }
bool operator!=(const Iterator& o) { return mIndex != o.mIndex; }
// ...
};
// Client 代碼
for (auto it = mgr.Begin(); it != mgr.End(); ++it) {
int id = (*it)->mPID; delete *it;
}
應用:STL 所有容器迭代器、資料庫游標、檔案系統遍歷。
意圖:在基類定義演算法骨架(FrameMethod),將具體步驟(SubMethod1/2)延遲到子類實現。
class TopFrame {
public:
void FrameMethod() { SubMethod1(); SubMethod2(); } // 非虛函數封裝流程
protected:
virtual void SubMethod1() = 0;
virtual void SubMethod2() = 0;
};
class Sub1 : public TopFrame { /* 實現具體步驟 */ };
關鍵:FrameMethod 為 non-virtual,防止子類破壞流程;子類只能覆寫 protected virtual 步驟。
意圖:定義一族演算法(場景),封裝並使其可互換。App 持有 Scene*,透過 SwitchScene 動態切換。
class Scene { virtual void Init()=0; virtual void Update()=0; virtual void Render()=0; virtual void Destroy()=0; };
class App {
Scene* mp = nullptr;
public:
void SwitchScene(Scene* p) { if(mp) mp->Destroy(); mp=p; mp->Init(); }
void Run() { if(mp) { mp->Update(); mp->Render(); } }
};
場景:遊戲場景切換、武器切換、壓縮演算法選擇、付費策略。
意圖:對象內部狀態改變時行為隨之改變,避免大量 if-else/switch。
class M16_Rifle {
M16_State *mpCurr, *mpNormal, *mpMuffler;
int mPower = 50;
public:
void Fire() { mpCurr->FireAudio(); }
void SwitchFireMode() {
mpCurr = (mpCurr == mpNormal) ? mpMuffler : mpNormal;
mpCurr->AdjustPower(this); // 狀態進入時調整屬性
}
};
優於 bool 標誌:狀態類封裝專屬邏輯(音效、火力),新增狀態只需新增類,符合開閉原則。
意圖:一對多依賴,主題(晶礦)變化時自動通知所有觀察者(重工廠、兵營)。
template<typename T> class IObservable {
std::set<IObserver<T>*> mObservers;
public:
void AddObserver(IObserver<T>* o) { mObservers.insert(o); }
void NotifyObservers(T ctx) { for(auto o:mObservers) o->Update(ctx); }
};
class Crystal : public IObservable<u32> { /* 采礦時 NotifyObservers(count) */ };
class Factory : public IObserver<u32> { void Update(u32 c) { if(c>200) /* 可建造 */ } };
應用:GUI 事件系統、訊息總線、股票行情推播、日誌框架。
意圖:將操作(移動、攻擊、採礦)封裝為命令對象,支援撤銷/重做、佇列、日誌。
class Command { virtual void Execute() = 0; };
class MoveCommand : public Command { SCV* mp; int mx, my; void Execute() { mp->Move(mx,my); } };
class Commander {
Command *mv, *atk, *rd, *mn, *st;
public:
void Move() { mv->Execute(); } /* ... */
};
擴展:命令存入 std::stack 即可實現 Undo/Redo。
意圖:在不破壞封裝前提下,捕獲對象內部狀態並外部化儲存,以便日後恢復。
template<typename T> class Memento {
T* mpt;
public:
Memento(T* pt) : mpt(new T(*pt)) {}
~Memento() { delete mpt; }
T* GetData() { return mpt; }
};
class Setting {
Memento<Setting>* CreateRestore() { return new Memento<Setting>(this); }
void Restore(Memento<Setting>* p) { /* 從 mpt 複製資料 */ }
};
測試輸出:
多次 CreateRestore / Restore 可實現多級回滾(如設置面板的「重置」、「撤銷」)。
| 模式 | 核心關鍵字 | 典型應用 |
|---|---|---|
| Iterator | 統一遍歷、封裝結構 | STL 容器、資料庫 Cursor |
| Template Method | 骨架固定、步驟虛擬 | 框架流程控制、文檔導出 |
| Strategy | 演算法族、運行期切換 | 場景管理、支付策略、壓縮 |
| State | 狀態類、行為隨狀態變 | 遊戲角色狀態、TCP 連線狀態 |
| Observer | 發布/訂閱、鬆耦合 | 事件總線、行情推送、MVC View 更新 |
| Command | 請求對象化、支援撤銷 | GUI 按鈕、巨集錄製、事務管理 |
| Memento | 狀態快照、外部化儲存 | 編輯器撤銷、遊戲存檔、設置備份 |
未完待續……後續將補充結構型與創建型模式實戰。