天天看点

设计模式学习笔记--装饰模式

定义:

在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

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.当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

继续阅读