裝飾者模式(Decorator Pattern)屬結構型設計模式,透過「組合」而非「繼承」在執行期動態為物件新增職責。本文提供完整 C++ 實作,包含 UML 類別圖對應程式碼、多層裝飾疊加示範、記憶體管理注意事項,並對比繼承方案優劣。
| 角色 | 類別 | 職責 |
|---|---|---|
| Component | CHuman | 定義被裝飾者介面(虛函數 Info(), Level()) |
| ConcreteComponent | CLiaoningHuman, CShanDongHuman | 具體被裝飾物件 |
| Decorator | Decorator | 繼承 Component,持有 Component 指標,定義裝飾介面 |
| ConcreteDecorator | CDecoratorWuDang, CDecoratorShaoLin, CDecoratorHuaShan | 具體裝飾行為(武功流派) |
#include <iostream>
#include <string>
using namespace std;
// ===== Component =====
class CHuman {
public:
virtual ~CHuman() = default;
virtual string Info() const { return "無資訊"; }
virtual int Level() const = 0; // 純虛函數
protected:
string m_info;
};
// ===== ConcreteComponent =====
class CLiaoningHuman : public CHuman {
public:
CLiaoningHuman() { m_info = "遼寧人"; }
int Level() const override { return 0; }
};
class CShanDongHuman : public CHuman {
public:
CShanDongHuman() { m_info = "山東人"; }
int Level() const override { return 0; }
};
// ===== Decorator (抽象裝飾者) =====
class Decorator : public CHuman {
public:
explicit Decorator(CHuman* human) : m_human(human) {}
virtual ~Decorator() { delete m_human; } // 負責釋放被裝飾者
string Info() const override = 0; // 強制子類實作
int Level() const override = 0;
protected:
CHuman* m_human;
};
// ===== ConcreteDecorators =====
class CDecoratorWuDang : public Decorator {
public:
explicit CDecoratorWuDang(CHuman* h) : Decorator(h) {}
string Info() const override { return m_human->Info() + " 學習了武當功夫"; }
int Level() const override { return m_human->Level() + 1; }
};
class CDecoratorShaoLin : public Decorator {
public:
explicit CDecoratorShaoLin(CHuman* h) : Decorator(h) {}
string Info() const override { return m_human->Info() + " 學習了少林功夫"; }
int Level() const override { return m_human->Level() + 2; }
};
class CDecoratorHuaShan : public Decorator {
public:
explicit CDecoratorHuaShan(CHuman* h) : Decorator(h) {}
string Info() const override { return m_human->Info() + " 學習了華山功夫"; }
int Level() const override { return m_human->Level() + 3; }
};
int main() {
// 遼寧人 → 武當 → 少林 → 華山
CHuman* person = new CLiaoningHuman();
person = new CDecoratorWuDang(person);
person = new CDecoratorShaoLin(person);
person = new CDecoratorHuaShan(person);
cout << person->Info() << endl; // 遼寧人 學習了武當功夫 學習了少林功夫 學習了華山功夫
cout << "武功等級: " << person->Level() << endl; // 6
// 山東人 → 武當 → 少林
person = new CShanDongHuman();
person = new CDecoratorWuDang(person);
person = new CDecoratorShaoLin(person);
cout << person->Info() << endl; // 山東人 學習了武當功夫 學習了少林功夫
cout << "武功等級: " << person->Level() << endl; // 3
// 記憶體由最外層 Decorator 析構遞歸釋放
delete person;
return 0;
}
CHuman 與 Decorator 必須宣告 virtual ~ClassName(),確保多層裝飾正確釋放記憶體。Decorator 建構子接收裸指標並接管所有權,析構時 delete m_human。現代 C++ 建議改用 std::unique_ptr<CHuman> 明確語意。CHuman,對客戶端呈現相同介面,實現透明疊加。| 維度 | 繼承 | 裝飾者模式 |
|---|---|---|
| 靈活度 | 編譯期靜態決定 | 執行期動態組合 |
| 類別爆炸 | 排列組合產生大量子類 | 線性新增裝飾類別 |
| 多重行為疊加 | 需多重繼承(複雜) | 自然支援鏈式疊加 |
| 封裝性 | 破壞封裝(存取 protected) | 僅透過公共介面互動 |
BufferedReader, GZIPInputStream 疊加)。裝飾者模式以「組合優於繼承」為核心哲學,提供比繼承更彈性的擴展機制。掌握其「抽象裝飾者持有元件介面、具體裝飾者轉呼叫並增強」的結構範本,即可優雅解決動態功能疊加問題。現代 C++ 實作時請搭配智慧指標管理生命週期,避免手動 new/delete 風險。