首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

設計模式筆記:深度解析 11 種行為型模式

     編輯:Java 綜合教學

設計模式筆記:深度解析 11 種行為型模式

行為型模式關注物件之間的通訊與職責分配,描述物件或類之間的交互模式。本文整理了 GoF 設計模式中的 11 種行為型模式,包含適用場景、核心原理、代碼實現與關鍵要點,助你靈活應對複雜業務邏輯設計。

1. 職責鏈模式

適用場景

  • 多個物件可處理同一請求,具體處理者需在運行時動態決定
  • 請求處理者集合需動態指定,支援動態增減處理節點

核心原理

鏈上每個物件持有統一處理介面與後繼者引用。請求從鏈首傳遞,各節點選擇自行處理或轉發給下一節點。客戶端無需知曉最終處理者,降低耦合度。

代碼實現 (C++ 風格)

// 抽象處理者
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 開始傳遞

2. 命令模式

適用場景

  • 將請求調用者與實現者解耦,支援命令排隊、記錄、撤銷
  • 需支援宏命令(組合多個命令)
  • 新增命令不影響既有代碼(開閉原則)

核心原理

將請求封裝為命令物件,內含執行邏輯與接收者引用。調用者僅持有命令介面,不知具體實現。命令可實現 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(); // 執行命令

3. 解釋器模式

適用場景

  • 特定領域語言(DSL)解析,如 SQL、正則表達式、規則引擎
  • 語法規則相對簡單,需動態解釋執行

核心差異:與組合模式比較

組合模式強調「部分-整體」樹狀結構的統一操作;解釋器模式在組合基礎上增加「語言翻譯」步驟,將輸入語言解析為語法樹(解釋器組合),各節點實現特定語法規則。

範例:字串搜尋語法

// 語法:#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);
    }
}

4. 迭代器模式

動機

提供統一介面遍歷聚合物件,不暴露內部結構。支援多種遍歷方式(正向、反向、過濾),同一聚合可同時存在多個迭代器。

外部迭代器實現

// 聚合介面
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; } // 自動釋放
    // 代理所有介面方法...
}

5. 中介者模式

意圖

  • 封裝一組物件的交互關係,將多對多依賴轉為一對多
  • 避免產生大量子類來分發行為
  • 降低同事物件耦合,提高復用性

實現

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); }
}

6. 備忘錄模式

意圖

在不破壞封裝前提下,捕獲物件內部狀態並外部化儲存,支援後續恢復(如撤銷功能、檢查點)。

關鍵角色

  • Originator(發起人):建立備忘錄、從備忘錄恢復狀態
  • Memento(備忘錄):儲存發起人狀態,對發起人透明,對管理者不透明(窄介面)
  • Caretaker(管理者):負責保管備忘錄,不操作內容

實現

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); // 恢復狀態

7. 觀察者模式

意圖

定義物件間一對多依賴,當主題狀態改變時,自動通知所有觀察者更新。支援鬆散耦合的事件驅動架構。

實現要點

// 觀察者介面
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) { /* 根據狀態更新自身 */ }
    }
}

進階變體

  • ChangeManager:多主題協同修改後統一通知,避免中間狀態觸發多次更新
  • 事件過濾:觀察者註冊時指定關注事件類型,減少無效通知

8. 狀態模式

意圖

允許物件在內部狀態改變時改變行為,看起來像修改了類。將狀態相關行為封裝於獨立狀態類中,Context 委派給當前狀態物件處理。

關鍵點

  • Context 維護當前 State 引用
  • State 介面定義行為契約
  • 具體 State 實現特定行為,可觸發狀態轉換
  • 狀態轉換邏輯可分佈在 Context 或 State 中

9. 策略模式

意圖

定義算法族,封裝各算法並使其可互換。算法變化不影響使用算法的客戶端(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(); // 切換為歸併排序

模板方法 vs 策略模式

模板方法基於繼承(靜態),策略模式基於組合(動態)。策略更靈活,支援運行時切換算法。

10. 模板方法模式

意圖

定義算法骨架,將特定步驟延遲到子類實現。子類可在不改變算法結構前提下重定義步驟。

實現規範

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 */ }
}

11. 訪問者模式

意圖

在不修改元素類前提下,為物件結構新增操作。將操作從元素類分離,集中於訪問者中。適合:元素結構穩定、操作頻繁變化、需對結構進行多種不相關操作。

核心機制:雙重分派

// 元素介面
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 種行為型模式的核心意圖與適用邊界,能讓你在面對複雜業務邏輯時,從容選擇最適合的設計方案,編寫出高內聚、低耦合、易擴展的優質代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved