天天看點

設計模式學習筆記--裝飾模式

定義:

在不必改變原類檔案和使用繼承的情況下,動态地擴充一個對象的功能。它是通過建立一個包裝對象,也就是裝飾來包裹真實的對象。

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.當不能采用生成子類的方法進行擴充時。一種情況是,可能有大量獨立的擴充,為支援每一種組合将産生大量的子類,使得子類數目呈爆炸性增長。另一種情況可能是因為類定義被隐藏,或類定義不能用于生成子類。

繼續閱讀