定義:
在不必改變原類檔案和使用繼承的情況下,動态地擴充一個對象的功能。它是通過建立一個包裝對象,也就是裝飾來包裹真實的對象。
UML圖:
形式:
(1) 裝飾對象和真實對象有相同的接口。這樣用戶端對象就能以和真實對象相同的方式和裝飾對象互動。 (2) 裝飾對象包含一個真實對象的引用(reference) (3) 裝飾對象接受所有來自用戶端的請求。它把這些請求轉發給真實的對象。 (4) 裝飾對象可以在轉發這些請求以前或以後增加一些附加功能。這樣就確定了在運作時,不用修改給定對象的結構就可以在外部增加附加的功能。在面向對象的設計中,通常是通過繼承來實作對給定類的功能擴充。
例子:
// 設計模式Demo.cpp : 定義控制台應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
//要被裝飾的對象基類(Component),這裡用人物基類表示
class BaseCharacter
{
public:
virtual void func() = 0;
};
//要被修飾的對象(ConcreateComponent),這裡用玩家表示
class Player : public BaseCharacter
{
public:
void func() override
{
cout<<"I am Character. I don't have any equipment"<<endl;
}
};
//裝飾基類(Decorator),這裡用裝備基類表示
class EquipmentBase : public BaseCharacter
{
private:
BaseCharacter* m_pCharacter;
public:
void setCharacter(BaseCharacter* c)
{
m_pCharacter = c;
}
//重寫function,執行character的func方法
void func() override
{
if (m_pCharacter)
m_pCharacter->func();
}
};
//具體裝飾類(ConcreateDecorater),這裡用武器表示
class Weapon : public EquipmentBase
{
private:
//增加一個字段
string m_weapon;
public:
void func() override
{
//先執行基類的方法
EquipmentBase::func();
//執行裝飾類特有的方法
m_weapon = "But now I have a gun!";
cout<<m_weapon<<endl;
}
};
//具體裝飾類(ConcreateDecorater),這裡用衣服表示
class Clothes : public EquipmentBase
{
public:
void equipCloth()
{
cout<<"But now I have clothes"<<endl;
}
void func() override
{
EquipmentBase::func();
equipCloth();
}
};
//用戶端
int _tmain(int argc, _TCHAR* argv[])
{
BaseCharacter* character = new Player();
Weapon* weapon = new Weapon();
Clothes* clothes = new Clothes();
/*
這裡可能有些不太恰當,所說的裝備并不是真正的裝備,而是裝備了裝備的玩家
即通過了裝備類,使玩家變成了有裝備的玩家
*/
//沒有裝備的玩家
cout<<"Before Equip:"<<endl;
character->func();
//裝備武器的玩家
cout<<"After Equip a weapon:"<<endl;
weapon->setCharacter(character);
weapon->func();
//再裝備衣服的玩家
cout<<"After Equip clothes:"<<endl;
clothes->setCharacter(weapon);
clothes->func();
system("pause");
return 0;
}
這個例子寫的是一個玩家和裝備之間的關系,但是稍微有些不恰當,例子中的裝備類并非僅僅表示一個裝備,由于裝備類繼承了玩家類,是以這裡表示的是裝備了裝備的玩家。
裝飾模式通過裝飾類,繼承被裝飾類,使裝飾類自身和被裝飾類接口相同。而内部封裝了一個被裝飾的對象引用(指針),我們可以更加靈活的在裝飾類中添加要增加的代碼,而且這樣支援嵌套裝飾,即有層次的裝飾。如上面的例子,先裝備武器再裝備衣服。 裝飾模式可以動态的添加功能,就增加功能來說,比生成子類更加靈活。
什麼時候使用裝飾模式?
1.需要擴充一個類的功能時,裝飾模式可以将裝飾部分和原本的類的核心功能分開,這樣更有利于功能劃分。多用組合,少用繼承! 2. 需要動态的給一個對象添加功能,這些功能可以再動态的撤銷。 3.需要增加由一些基本功能的排列組合而産生的非常大量的功能,進而使繼承關系變的不現實。像上面的例子,想先穿衣服再拿武器也是可以的,而繼承沒法做到這點。 4.當不能采用生成子類的方法進行擴充時。一種情況是,可能有大量獨立的擴充,為支援每一種組合将産生大量的子類,使得子類數目呈爆炸性增長。另一種情況可能是因為類定義被隐藏,或類定義不能用于生成子類。