大话设计模式 —— 第六章《装饰模式》C++ 代码实现

本文介绍了装饰模式的概念、优缺点及应用场景,详细解释了如何利用装饰模式为对象动态添加职责,同时提供了C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

概念

介绍

优点

缺点

应用场景

装饰模式的重点


概念


装饰器模式是一种属于结构型的设计模式,它通过一层一层地包装类方式来为类增加新的方法,本质是利用组合,同时也利用了继承。与单纯的继承相比,它更加灵活,因为装饰类之间可以动态地自由组合来添加功能。

给对象添加方法的方式有多种,通常,当说到给对象添加方法时,最直接的就是直接在该对象的类中增加新的方法,但这样在最上方增加方法,不仅更改了原来的代码结构,还会让代码看起来十分臃肿;然后,我们就能想到继承,直接新增加一个类来继承,在子类中添加方法,然而这样做并不够灵活,而且在不断增加方法时,还会出现多重继承的现象,导致代码结构很乱;那么,这时候就需要另一种方式了,这种方式就是组合的方式。


介绍


装饰模式(decorator):

  • 表示动态的给一个对象添加一些新的功能(利用子类继承父类也可以实现),但是比生成子类方式更灵活。也叫装饰者模式或者装饰器模式、包装器模式。也是继承关系的一种代替方案。

 

装饰模式UML图

 

  • Component(抽象组件):可以是抽象类或者接口,可以给这些对象动态添加职责。真实对象和装饰者对象有相同的接口,这样客户端不用知道内部有装饰者对象(Decorator)存在的,还是以之前处理真实对象的相同方式来和装饰者对象交互。
  • ConcreteComponent(具体组件 ):是抽象组件的一个子类,具体组件的实例称为“被装饰者“,也可以给这个对象添加一些其他功能。
  • Decorator(抽象装饰类):也是抽象组件的一个子类,但抽象装饰类中还包含一个抽象组件声明的变量以保存“被装饰者“的引用。装饰可以是一个抽象类也可以是一个非抽象类,如果是非抽象类,该类的实例称为”装饰者“。
  • ConcreteDecorato (具体装饰):是抽象装饰类的一个非抽象子类,具体装饰的实例称为“装饰者“。只对抽象装饰类做出具体的实现,它还起到了给Component添加职责的功能。

优点


  • 装饰者模式与继承关系的目的都是要扩展对象的功能,但是装饰者模式可以提供比继承更多的灵活性,它可以动态的来扩展一个对象的功能。继承的话会导致子类个数增加。而装饰者模式不会出现这种情况,所以说装饰者模式扩展功能强。
  • 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
  • 把类的装饰功能从类中搬移去除,这样可以简化原有的类。
  • 装饰模式降低系统的耦合度,可以动态的增加或删除对象的职责. 具体组件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体组件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
  • 在不改变原有代码的情况下,把类的核心功能和装饰功能区分开了,并能动态扩展一个对象的新功能。
  • 被装饰者和装饰者是松耦合关系。由于装饰仅仅依赖于抽象组件,因此具体装饰只知道它要装饰的对象是抽象组件某一个子类的实例,但不需要知道是哪一个具体子类。

缺点


  • 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
  • 装饰模式会导致设计中出现许多小类,大量小对象会占据内存。一定程度上影响了性能。如果过度使用,会使程序变得很复杂。
  • 因为所有对象都是继承于(抽象组件)Component, 所以如果Component内部结构发生改变,则不可避免地影响所有子类(装饰者和被装饰者),如果基类改变,势必影响对象的内部。
     
  • 比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐,所以只在必要的时候使用装饰者模式。
     

 


应用场景


  • 需要动态的、透明的为一个对象添加功能,而又不影响到该类的其他对象。
  • 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
  • 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
  • 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

装饰模式的重点


  • 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
  • 装饰对象包含一个具体对象的引用(reference)。
  • 装饰对象接受所有来自客户端的请求。它把这些请求转发给具体的对象。
  • 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

装饰模式和桥接模式的区别:

  •  两个模式都是为了解决过多子类对象的问题,桥接模式是对象自身有过多的维度,造成过多的子类。而让维度分类后在搭建一个桥梁来联系起来。 而装饰模式是解决在增加新功能的时候产生多个类的问题。

和建造者模式的区别:

  • 建造者模式要求建造的过程必须是稳定的,而装饰模式的建造过程是不稳定的,可以有各种各样的组合方式。

与代理模式的区别:

  • 其实装饰者模式和代理模式很像,但是两者的目的不尽相同。装饰者模式是以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案;而代理模式则是一个给对象提供一个代理对象,并由代理对象来控制对原有对象的引用。
  • 装饰者模式为本装饰的对象进行功能扩展;代理模式对代理对象进行控制,但不做功能扩展

C++代码实现大话数据模式:

#include<iostream>
#include<string>
using namespace std;

class Person   //定义一个Component对象接口,显示出装扮后的装饰
{
private:
	std::string m_name;
public:
	virtual ~Person() = default;
	Person() = default;
	Person(std::string name)
	{
		m_name = name;
	}
	virtual void Show()
	{
		std::cout << "装饰的" << m_name << std::endl;
	}
};

// 装饰抽象类 Decorator:Finery 类需要持有一个真实对象的引用,也就是Person对象
class Finery : public Person
{
protected:
	Person *m_component;
public:
	virtual ~Finery() = default;
	void Decorator(Person* component);
	void Show()override;

};
void Finery::Decorator(Person* component)
{
	m_component = component;
}
void Finery::Show()
{
	if (m_component != nullptr)
	{
		m_component->Show();
	}
}

// 定义一个具体真实的对象ConcreteComponent,该类的实例称为“被装饰者“
class TShirts final : public Finery  // final关键字 表示该类不能作基类
{
public:
	void Show() override;
};
void TShirts::Show()
{
	std::cout << "大T恤  ";
	Finery::Show();
}

//ConcreteDecorator类
class BigTrouser final :public Finery
{
public:
	void Show()override;
};
void BigTrouser::Show()
{
	std::cout << "垮裤  ";
	Finery::Show();
}

//ConcreteDecorator类
class Sneakers  final :public Finery
{
public:
	void Show()override;

};
void Sneakers::Show()
{
	std::cout << "破球鞋  ";
	Finery::Show();
}

//ConcreteDecorator类
class Suit final :public Finery
{
public:
	void Show()override;
};

void Suit::Show()
{
	std::cout << "西装  ";
	Finery::Show();
}

//ConcreteDecorator类
class Tie final :public Finery
{
public:
	void Show()override;
};
void Tie::Show()
{
	std::cout << "领带  ";
	Finery::Show();
}

//ConcreteDecorator类
class LeatherShoes final :public Finery
{
public:
	void Show()override;

};
void LeatherShoes::Show()
{
	std::cout << "皮鞋  ";
	Finery::Show();
}

int main()
{
	Person* xc = new Person("小菜");

	std::cout << "第一种装扮:" << std::endl;

	Sneakers* pqx = new Sneakers;
	BigTrouser* kk = new BigTrouser;
	TShirts* dtx = new TShirts;

	pqx->Decorator(xc);
	kk->Decorator(pqx);
	dtx->Decorator(kk);
	dtx->Show();


	std::cout << "第二种装扮:" << std::endl;

	LeatherShoes* px = new LeatherShoes;
	Tie* ld = new Tie;
	Suit* xz = new Suit;

	px->Decorator(xc);
	ld->Decorator(px);
	xz->Decorator(ld);
	xz->Show();

	if (xc != nullptr)
	{
		delete xc;
		xc = nullptr;
	}
	if (pqx != nullptr)
	{
		delete pqx;
		pqx = nullptr;
	}
	if (kk != nullptr)
	{
		delete kk;
		kk = nullptr;
	}
	if (dtx != nullptr)
	{
		delete dtx;
		dtx = nullptr;
	}
	if (px != nullptr)
	{
		delete px;
		px = nullptr;
	}
	if (ld != nullptr)
	{
		delete ld;
		ld = nullptr;
	}
	if (xz != nullptr)
	{
		delete xz;
		xz = nullptr;
	}
	system("pause");
	return 0;
}

运行后截图:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值