c++设计模式之装饰模式

血红的双手。 提交于 2019-12-19 23:58:19

前言

装饰,顾名思义,就是对现有的物件进行优化,比如加一些好看的物件等等。例如拍出来的照片需要进行美化,刚建好的房子需要装修等等。在软件设计中,有时候也需要对现有的类进行“装饰”,以满足客户的要求。

装饰模式的定义

装饰模式:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
装饰模式能够实现动态的为对象添加新的功能,并且是从类的外部来增加新的功能。如果从类的内部进行添加新的功能,就违反了设计模式的开闭原则。装饰模式就是把复杂的工作简单化,分散化。

装饰模式的结构

装饰模式的UML类图如下所示:
在这里插入图片描述
可以看到装饰模式的主要角色有以下几个:
1.抽象构件:定义一个抽象接口以规范准备接收附加责任的对象。
2.具体构件:实现抽象构件,通过装饰角色为其添加一些职责
3.抽象装饰:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
4.具体装饰:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

装饰模式示例

接下来来看一下一个简单的实例吧。
示例简介:想必大家都知道绝地求生这款游戏吧,开局一条狗,啊呸,说顺口了,是开局一个人,要想活下来就必须捡装备来武装自己才能有能力对抗啊。
先构造一个抽象士兵类,起抽象构件角色

class AbSoldier//抽象士兵类 
{
	public:
		virtual void attack() = 0;
};

该类定义了一个attack的接口。
接下来构造了一个具体士兵类:

class Soldier:public AbSoldier
{
	public:
		virtual void attack()
		{
			cout << "soldier attack" << endl;
		}
};

这是一个没有武器的士兵。
再来构建一个装饰类

class AbDecorator:public AbSoldier
{
	protected:
		AbSoldier *mSoldier;
	public:
		void decorator(AbSoldier *Soldier)
		{
			this->mSoldier = Soldier;
		}
		virtual void attack()
		{
			mSoldier->attack();
		}		
};

继承抽象的士兵类。
接下来就是具体的装饰类,这里做了两个装饰类,一个是枪,一个是刀。

class GunDecorator:public AbDecorator
{
	public:
		void attack()
		{
			take_gun();
			mSoldier->attack();
		}
		void take_gun()
		{
			cout << "soldier take the gun" << endl;
		}
};
class KnifeDecorator:public AbDecorator
{
	public:
		void attack() 
		{
			take_knife();
			mSoldier->attack();
		}
		void take_knife()
		{
			cout << "soldier take the knife " << endl;
		}
};

完整代码如下:

#include <iostream>
using namespace std;
class AbSoldier//抽象士兵类 
{
	public:
		virtual void attack() = 0;
};
class Soldier:public AbSoldier
{
	public:
		virtual void attack()
		{
			cout << "soldier attack" << endl;
		}
};
class AbDecorator:public AbSoldier
{
	protected:
		AbSoldier *mSoldier;
	public:
		void decorator(AbSoldier *Soldier)
		{
			this->mSoldier = Soldier;
		}
		virtual void attack()
		{
			mSoldier->attack();
		}		
};
class GunDecorator:public AbDecorator
{
	public:
		void attack()
		{
			take_gun();
			mSoldier->attack();
		}
		void take_gun()
		{
			cout << "soldier take the gun" << endl;
		}
};
class KnifeDecorator:public AbDecorator
{
	public:
		void attack() 
		{
			take_knife();
			mSoldier->attack();
		}
		void take_knife()
		{
			cout << "soldier take the knife " << endl;
		}
};
int main()
{
	Soldier *pSoldier = new Soldier();
	AbDecorator *pAbDecorator = new AbDecorator();
	pAbDecorator->decorator(pSoldier);
	GunDecorator *pGunDecorator = new GunDecorator();
	pGunDecorator->decorator(pAbDecorator);
	pGunDecorator->attack();
	KnifeDecorator *pKnifeDecorator = new KnifeDecorator();
	pKnifeDecorator->decorator(pAbDecorator);
	pKnifeDecorator->attack();
	return 0;
}

运行代码结果如下:
在这里插入图片描述
可以看到,士兵都被装饰器给武装起来了,有了装饰器,士兵就拥有了原来没有的新功能了。
看完实例,我们来总结一下装饰模式的应用场景:
1.当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时
2.当对象的功能要求可以动态地添加,也可以再动态地撤销时
3.当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰模式却很好实现。

装饰模式的优缺点

装饰模式的主要优点有:
1.采用装饰模式扩展对象的功能比采用继承方式更加灵活。
2.可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。

其主要缺点是:装饰模式增加了许多子类,如果过度使用会使程序变得很复杂

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!