C++设计模式—装饰器模式

产生背景

很多情况下,当一个类已经存在,并且可以对外提供核心功能时。但是,某个时刻,希望对这个类进行功能增强,当然,我们可以修改原来的类,并增加对应的增强功能

但是,这种方式违背了“开-闭”原则,需要修改原来的代码;而且不够灵活,如果有某个时刻又不想使用这个功能,又需要修改原来的代码,显然,这不是一个很好的解决方案。因此,就引出了装饰器这个东东。

装饰器模式概述

概念

定义:动态地给一个对象添加一些额外的职责。就添加功能来说,Decorator模式相比生成子类更为灵活。属于结构型模式

本质在面向对象的设计中,我们应该尽量使用对象组合,而不是对象继承来扩展和复用功能

装饰器模式就是基于对象组合的方式,可以很灵活的给对象添加所需要的功能。
装饰器模式的本质就是动态组合。动态是手段,组合才是目的。总之,装饰模式就是通过把复杂的功能简单化,分散化,然后在运行期间,根据需要来动态组合的模式。它使得我们可以给某个对象而不是整个类添加一些功能。

UML图

模式中的角色

  • 抽象构建(Component):定义一个抽象接口,用以给这些对象动态地添加职责。
  • 具体构建(ConcreteComponent):定义一个具体的对象,也可以给这个对象添加一些功能。
  • 装饰类(Decorator): 装饰抽象类,继承了Component,从外类来扩展Component类的功能。
  • 具体装饰者(ConcretorDecorator):负责给构建对象添加功能。

举例
为一个蛋糕添加装饰。蛋糕店刚生产出来的蛋糕是最原始的,只是一个蛋糕原型,我们需要再这个蛋糕上加上奶油,加上巧克力,加上水果,写上字等等,将原始蛋糕作为一个Cake类,我们给这个Cake类的对象作装饰,为了不破坏开放-封闭原则,也为了更好的拓展,我们不能直接在Cake这个类里修改,而通过装饰器来给这个蛋糕做装饰。

代码示例:

#pragma once
#include <iostream>

class Cake //一个原始的抽象类蛋糕
{

public:
	virtual void showCake() = 0;
	virtual ~Cake() {};
	std::string name;
};

class ConcreteCake :public Cake//具体的蛋糕类
{
public:
	ConcreteCake()
	{
		name = "原始蛋糕";
	}
	void showCake() { std::cout << name.c_str() << std::endl; };
	virtual  ~ConcreteCake() {};
};

#pragma once
#include "test.h"
#include<iostream>
using namespace std;


class CakeDecrator :public Cake
{
protected:
	Cake* pCake;  //维护一个Cake对象的引用,为Cake对象添加装饰
public:
	virtual void showCake() = 0;
	virtual	~CakeDecrator() {};
};

class CakeDecratorMilk : public CakeDecrator//具体添加牛奶的装饰类
{
public:
	CakeDecratorMilk(Cake* pCake)
	{
		this->pCake = pCake;
	}
	void showCake()
	{
		this->name = pCake->name + "加奶油";
		cout << name<<endl;
	};
	virtual ~CakeDecratorMilk() {};
};

class CakeDecratorCholate : public CakeDecrator//具体添加巧克力的类
{
public:
	CakeDecratorCholate(Cake* pCake)
	{
		this->pCake = pCake;
	}
	void showCake()
	{
		this->name = pCake->name + "加巧克力";
		std::cout << name<<endl;
	};
	virtual ~CakeDecratorCholate() {};
};


#include "d.h"

int main()
{
	ConcreteCake* ConCake = new ConcreteCake();
	ConCake->showCake();

	CakeDecratorMilk* MilkCake = new CakeDecratorMilk(ConCake);
	MilkCake->showCake();
	CakeDecratorCholate* ChoCake = new CakeDecratorCholate(ConCake);
	ChoCake->showCake();


	CakeDecratorCholate* CMCake = new CakeDecratorCholate(MilkCake);
	CMCake->showCake();
	
	delete ConCake;
	delete MilkCake;
	delete ChoCake;
	delete CMCake;
	return 0;
}

优点

  • 每个装饰对象只关心自己的功能,不需要关心如何被添加到对象当中。
  • 类的核心职责与动态添加的职责是分离的。如果再向主类中添加新的功能,一是违反了开放封闭原则,二是增加了主类的复杂度。
  • 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。
  • 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

装饰模式的缺点

使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。

适用场景

  • 当需要为已有功能动态地添加更多功能时。
  • 类的核心功能无需改变,只是需要添加新的功能时。

猜你喜欢

转载自blog.csdn.net/qq_43313035/article/details/89917915