行為型模式關注物件之間的通訊與職責分配,描述物件或類之間的交互模式。本文整理了 GoF 設計模式中的 11 種行為型模式,包含適用場景、核心原理、代碼實現與關鍵要點,助你靈活應對複雜業務邏輯設計。
鏈上每個物件持有統一處理介面與後繼者引用。請求從鏈首傳遞,各節點選擇自行處理或轉發給下一節點。客戶端無需知曉最終處理者,降低耦合度。
// 抽象處理者
class HelpHandler {
protected:
HelpHandler* _successor;
public:
HelpHandler(HelpHandler* successor = nullptr) : _successor(successor) {}
virtual void HandleEvent(Event e) {
if (_successor) _successor->HandleEvent(e);
}
virtual ~HelpHandler() {}
};
// 具體處理者:按鈕
class Button : public HelpHandler {
public:
Button(HelpHandler* h) : HelpHandler(h) {}
void HandleEvent(Event e) override {
if (canDealWith(e)) { doSomething(); }
else { HelpHandler::HandleEvent(e); } // 轉發給下一個
}
};
// 具體處理者:對話框
class Dialog : public HelpHandler {
public:
Dialog(HelpHandler* h) : HelpHandler(h) {}
void HandleEvent(Event e) override {
if (canDealWith(e)) { doSomething(); }
else { HelpHandler::HandleEvent(e); }
}
};
// 客戶端組裝鏈
// dialog 為鏈尾,button 指向 dialog
HelpHandler* dialog = new Dialog(nullptr);
HelpHandler* button = new Button(dialog);
button->HandleEvent(event); // 請求從 button 開始傳遞
將請求封裝為命令物件,內含執行邏輯與接收者引用。調用者僅持有命令介面,不知具體實現。命令可實現 Undo/Redo,支援事務性操作。
// 命令介面
class Command {
public:
virtual void Execute() = 0;
virtual void Undo() = 0; // 支援撤銷
virtual ~Command() {}
};
// 具體命令
class OpenCommand : public Command {
Application* _app;
public:
OpenCommand(Application* app) : _app(app) {}
void Execute() override { _app->AddDocument(); }
void Undo() override { _app->CloseDocument(); }
};
// 調用者
class MenuItem {
Command* _cmd;
public:
MenuItem(Command* cmd) : _cmd(cmd) {}
void Click() { _cmd->Execute(); }
};
// 客戶端
Application app;
Command* open = new OpenCommand(&app);
MenuItem item(open);
item.Click(); // 執行命令
組合模式強調「部分-整體」樹狀結構的統一操作;解釋器模式在組合基礎上增加「語言翻譯」步驟,將輸入語言解析為語法樹(解釋器組合),各節點實現特定語法規則。
// 語法:#prefix 開頭,$suffix 結尾,%contains 包含
// 輸入 "#hello$world" → 解析為:StartsWith("hello") + EndsWith("world")
// 抽象表達式
class Expression {
public:
virtual bool Interpret(String context) = 0;
};
// 終結符表達式
class StartsWithExpression : public Expression {
String _prefix;
public:
StartsWithExpression(String p) : _prefix(p) {}
bool Interpret(String context) override {
return context.startsWith(_prefix);
}
};
// 非終結符表達式(組合)
class AndExpression : public Expression {
Expression* _left; Expression* _right;
public:
AndExpression(Expression* l, Expression* r) : _left(l), _right(r) {}
bool Interpret(String context) override {
return _left->Interpret(context) && _right->Interpret(context);
}
}
提供統一介面遍歷聚合物件,不暴露內部結構。支援多種遍歷方式(正向、反向、過濾),同一聚合可同時存在多個迭代器。
// 聚合介面
template <class Item>
class Aggregate {
public:
virtual long Count() = 0;
virtual Item& GetItem(long index) = 0;
};
// 迭代器介面
template <class Item>
class Iterator {
public:
virtual void First() = 0;
virtual void Next() = 0;
virtual bool IsDone() = 0;
virtual Item CurrentItem() = 0;
};
// 具體迭代器
template <class Item>
class ConcreteIterator : public Iterator<Item> {
Aggregate<Item>& _aggregate;
long _current;
public:
ConcreteIterator(Aggregate<Item>& a) : _aggregate(a), _current(0) {}
void First() override { _current = 0; }
void Next() override { _current++; }
bool IsDone() override { return _current >= _aggregate.Count(); }
Item CurrentItem() override { return _aggregate.GetItem(_current); }
};
// 使用範例
ConcreteIterator<Item> iter(aggregate);
for (iter.First(); !iter.IsDone(); iter.Next()) {
Item& item = iter.CurrentItem();
// 處理 item
}
// 內部迭代器:遍歷邏輯封裝在迭代器內部
class ListTraverser {
Iterator<Item>& _iter;
public:
ListTraverser(Iterator<Item>& iter) : _iter(iter) {}
bool Traverse() {
for (_iter.First(); !_iter.IsDone(); _iter.Next()) {
if (!ProcessItem(_iter.CurrentItem())) return false;
}
return true;
}
protected:
virtual bool ProcessItem(const Item&) = 0; // 子類實現具體處理
};
// 迭代器工廠 + Proxy 模式管理生命週期
class IteratorProxy : public Iterator<Item> {
Iterator<Item>* _real;
public:
IteratorProxy(Iterator<Item>* real) : _real(real) {}
~IteratorProxy() { delete _real; } // 自動釋放
// 代理所有介面方法...
}
class DialogDirector {
Button& _ok;
Button& _cancel;
ListBox& _fontList;
public:
DialogDirector(Button& ok, Button& cancel, ListBox& font)
: _ok(ok), _cancel(cancel), _fontList(font) {}
// 統一處理同事物件通知
void WidgetChanged(Widget* sender) {
if (sender == &_fontList) {
_ok.SetEnabled(!_fontList.GetSelection().IsEmpty());
} else if (sender == &_ok) {
ApplyFontChange();
}
}
};
// 同事物件基類
class Widget {
DialogDirector* _mediator;
public:
Widget(DialogDirector* m) : _mediator(m) {}
void Changed() { _mediator->WidgetChanged(this); }
}
在不破壞封裝前提下,捕獲物件內部狀態並外部化儲存,支援後續恢復(如撤銷功能、檢查點)。
class Originator {
String _state;
public:
// 建立備忘錄(僅發起人可訪問內部)
class Memento {
String _state;
Memento(String s) : _state(s) {}
friend class Originator;
};
Memento* CreateMemento() { return new Memento(_state); }
void SetMemento(Memento* m) { _state = m->_state; }
};
// 客戶端
Originator originator;
Originator::Memento* saved = originator.CreateMemento();
// ... 業務操作 ...
originator.SetMemento(saved); // 恢復狀態
定義物件間一對多依賴,當主題狀態改變時,自動通知所有觀察者更新。支援鬆散耦合的事件驅動架構。
// 觀察者介面
class Observer {
public:
virtual void Update(Subject* subject) = 0;
};
// 主題介面
class Subject {
std::list<Observer*> _observers;
public:
void Attach(Observer* o) { _observers.push_back(o); }
void Detach(Observer* o) { _observers.remove(o); }
void Notify() {
for (auto o : _observers) o->Update(this);
}
};
// 具體主題
class ConcreteSubject : public Subject {
int _state;
public:
void SetState(int s) { _state = s; Notify(); }
int GetState() { return _state; }
};
// 具體觀察者
class ConcreteObserver : public Observer {
void Update(Subject* s) override {
ConcreteSubject* sub = dynamic_cast<ConcreteSubject*>(s);
if (sub) { /* 根據狀態更新自身 */ }
}
}
允許物件在內部狀態改變時改變行為,看起來像修改了類。將狀態相關行為封裝於獨立狀態類中,Context 委派給當前狀態物件處理。
定義算法族,封裝各算法並使其可互換。算法變化不影響使用算法的客戶端(Context)。
// 策略介面
class Strategy {
public:
virtual void Execute() = 0;
};
// 具體策略
class QuickSort : public Strategy { void Execute() override { /* 快排 */ } };
class MergeSort : public Strategy { void Execute() override { /* 歸併 */ } };
// Context 組合策略(運行時可切換)
class SortContext {
Strategy* _strategy;
public:
SortContext(Strategy* s) : _strategy(s) {}
void SetStrategy(Strategy* s) { _strategy = s; }
void Sort() { _strategy->Execute(); }
}
// 使用
SortContext ctx(new QuickSort());
ctx.Sort(); // 快速排序
ctx.SetStrategy(new MergeSort());
ctx.Sort(); // 切換為歸併排序
模板方法基於繼承(靜態),策略模式基於組合(動態)。策略更靈活,支援運行時切換算法。
定義算法骨架,將特定步驟延遲到子類實現。子類可在不改變算法結構前提下重定義步驟。
class AbstractClass {
public:
// 模板方法:final 防止被重寫,定義算法骨架
void TemplateMethod() {
Step1(); // 固定步驟
PrimitiveOp1(); // 可變步驟(抽象)
Step2();
PrimitiveOp2(); // 可變步驟(抽象)
Step3();
}
protected:
virtual void PrimitiveOp1() = 0; // 必須實現
virtual void PrimitiveOp2() = 0;
private:
void Step1() { /* 通用邏輯 */ }
void Step2() { /* 通用邏輯 */ }
void Step3() { /* 通用邏輯 */ }
};
class ConcreteClass : public AbstractClass {
void PrimitiveOp1() override { /* 具體實現 A */ }
void PrimitiveOp2() override { /* 具體實現 B */ }
}
在不修改元素類前提下,為物件結構新增操作。將操作從元素類分離,集中於訪問者中。適合:元素結構穩定、操作頻繁變化、需對結構進行多種不相關操作。
// 元素介面
class Equipment {
public:
virtual void Accept(EquipmentVisitor* v) = 0;
};
// 具體元素
class FloppyDisk : public Equipment {
public:
void Accept(EquipmentVisitor* v) override {
v->VisitFloppyDisk(this); // 關鍵:調用訪問者對應方法
}
};
// 訪問者介面
class EquipmentVisitor {
public:
virtual void VisitFloppyDisk(FloppyDisk* f) = 0;
virtual void VisitBus(Bus* b) = 0;
// ... 其他元素對應方法
};
// 具體訪問者:庫存統計
class InventoryVisitor : public EquipmentVisitor {
int _total = 0;
public:
void VisitFloppyDisk(FloppyDisk* f) override { _total += f->GetQuantity(); }
void VisitBus(Bus* b) override { _total += b->GetQuantity(); }
int GetTotal() { return _total; }
};
// 使用
EquipmentVisitor* visitor = new InventoryVisitor();
for (auto eq : equipmentList) eq->Accept(visitor);
| 優點 | 缺點 |
|---|---|
| 新增操作容易(只加訪問者) | 新增元素類困難(需修改所有訪問者) |
| 相關操作集中,職責清晰 | 破壞封裝(訪問者需訪問元素內部狀態) |
| 可跨層級訪問複雜結構 | 實現複雜,理解門檻高 |
掌握這 11 種行為型模式的核心意圖與適用邊界,能讓你在面對複雜業務邏輯時,從容選擇最適合的設計方案,編寫出高內聚、低耦合、易擴展的優質代碼。