设计模式之装饰模式

当系统需要新功能的时候,是向旧系统的类中添加新代码,而不是更改已有代码,这符合开放封闭原则,而装饰模式可以很好的做到这一点,装饰模式是把类中的装饰功能从类中抽象出去,这样可以简化原有的类,有效地把类的核心职责和装饰功能区分开了。而且可以去除相关类中重复的装饰逻辑。

装饰模式的UML类图如下:

在这里插入图片描述
本UML类图借用《大话设计模式》的UML类图,可能上面的解释部分不是很好理解,这里再重新用大白话解释一下:

Component类:是一个抽象的类,是被装饰者的抽象类。比如苹果手机,华为手机是我们要装饰的目标,是被装饰者,那么可以将它们抽象为一个手机类,即Component类,然后苹果手机类和华为手机类继承手机类

ConcreteComponent类:是具体的被装饰者类,比如上述的苹果手机和华为手机

Decorator类:是装饰抽象类

ConcreteDecoratorA和ConcreteDecoratorB是具体的装饰类,通过它们给被装饰对象进行装饰。

而装饰模式的具体用法通过一两句话实在是难以描述,请通过下面的例子来进行理解。

#include<iostream>
using namespace std;

//抽象类,对应UML类图component
//被装饰者可能不止一个,它是可能的变化,因此先把他们抽象出一个类来,符合开放-封闭原则
class Phone
{
public:
	Phone() {}
	virtual ~Phone() {}
	virtual void ShowDecorate() = 0;
};

//具体的手机类,其对象就是要修饰的对象,对应UML类图concreteComponent
class iPhone : public Phone
{
private:
	string m_name; //手机名称
public:
	iPhone(string name) : m_name(name) {}
	~iPhone() {}

	void ShowDecorate() 
	{ 
		cout << m_name << "的装饰" << endl; 
	}
};

//抽象装饰类,对应UML类图Decorator类
//装饰方法可能不止一种,因此先将它们抽象出一个类来,符合开放-封闭原则
class DecoratorPhone : public Phone
{
private:
	Phone* m_phone;  //该指针所指对象就是要装饰的手机对象
public:
	DecoratorPhone(Phone* phone) : m_phone(phone) {}
	virtual void ShowDecorate() 
	{ 
		m_phone->ShowDecorate();
	}
};

//具体的装饰类A,对应UML类图ConcreteDecoratorA
class DecoratorPhoneA : public DecoratorPhone
{
public:
	DecoratorPhoneA(Phone* phone) : DecoratorPhone(phone) {}
	//因为创建装饰类A的对象时,要将被修饰对象传递给该构造函数,因此装饰类A中指针m_phone指向的是被修饰对象
	void ShowDecorate()
	{
		DecoratorPhone::ShowDecorate(); AddDecorate();
	}
	/*先调用抽象装饰类中的showDecorate函数,装饰类中的showDecorate函数会去调用m_phone所指对象的showDecorate函数,即被装饰对象的showDecorate函数,当被装饰对象中的showDecorate函数调用完后,调用装饰函数*/
private:
	void AddDecorate() 
	{
		cout << "增加挂件" << endl; 
	} //增加的装饰
};

//具体的装饰类B,对应UML类图的ConcreteDecoratorB
class DecoratorPhoneB : public DecoratorPhone
{
public:
	DecoratorPhoneB(Phone* phone) : DecoratorPhone(phone) {}
	//在创建装饰类B的对象时会把装饰类A的对象作为参数传入该构造函数,故装饰B类中m_phone指针指向的是装饰A类对象
	void ShowDecorate() 
	{
		DecoratorPhone::ShowDecorate(); AddDecorate(); 
	}
	/*
	* 1.装饰类B的showDecorate先调用抽象装饰类中的showDecorate函数,再调用装饰B类的装饰函数
		* 2抽象装饰类中的showDecorate函数会去调用m_phone指针所指对象的showDecorate函数,即装饰类A的showDecorate函数
			* 3装饰类A的showDecorate函数会先去调用抽象装饰类中的showDecorate函数,再去调用装饰A类的装饰函数
				*4抽象装饰类中的showDecorate又会去调用m_phone所指对象的showDecorate函数,即被装饰对象的showDecorate函数,showDecorate调用完成后,
				回到第3步去调用A的装饰函数,调用完成后,装饰类A中的showDecorate函数调用完毕,那么第2步也就完成,回到第一步去调用装饰B类的装饰函数,调用完成后,装饰B的showDecorate函数调用完成
					
*/
private:
	void AddDecorate() 
	{
		cout << "屏幕贴膜" << endl; 
	} //增加的装饰
};

int main()
{
	Phone* iphone = new iPhone("6300");
	Phone* dpa = new DecoratorPhoneA(iphone); //装饰,增加挂件
	Phone* dpb = new DecoratorPhoneB(dpa);    //装饰,屏幕贴膜
	dpb->ShowDecorate();
	delete dpa;
	delete dpb;
	delete iphone;
	return 0;
}

仔细理清上述代码,就会对装饰模式有一个更加清晰的认识,个人感觉,在不断地给装饰对象添加功能的时候,其背后的逻辑就像是一个套娃…

学习一个设计模式,除了学习它的核心思想以外,我们还需要学习它的优缺点以及使用场景。

优点:

  1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性,因为装饰模式可以动态添加,动态取消功能。
  2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

缺点:

  1. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
  2. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

适用场景:

以下情况使用Decorator模式

  1. 需要扩展一个类的功能,或给一个类添加附加职责。
  2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
  4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北冥有鱼丶丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值