设计模式第四节-装饰器模式

前言

由于设计模式章节将贴出大量伪代码,为了压缩代码长度方便大家查看,因此代码段中与设计模式无关的代码,如构造函数、或是成员函数public、private、protect属性等均未写出。文章中若有说明不清晰或是有歧义、错误的地方欢迎大家评论指正,谢谢大家。


一、定义

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


二、定义的白话叙述

上述装饰器模式的定义可能有些晦涩,用白话来说就是在不改变一个类原有代码的基础上扩展该类的功能。
例如我们现在有下面一个getChar类,给入一个数字,输出一个字符。

class getChar
{
	char numToChar(int pos)
	{
		return pos;
	}
};

现在我们想对numToChar进行改造,实现输入1-26数字,输出对应坐标的小写字母。如果输入的数字不在范围内,返回空字符。常规的做法有2种:
1、改造现有getChar类的接口。
2、继承将numToChar设置为虚函数,继承getChar类实现一个新的类,实现numToChar接口。
而使用装饰器模式的做法是:实现一个新的类,类内包含getChar类的对象,并实现一个numToChar接口。这样用户直接将代码如下:

class getChar
{
public:
	char numToChar(int pos)
	{
		return pos;
	}
};

class getEng
{
public:
	getEng(getChar* ins)
	{
		m_ins = ins;
	}
	char numToChar(int pos)
	{
		if(pos < 1 || pos > 26 || m_ins == nullptr)
		{
			return '';
		}
		else
		{
			//'a'对应的十进制数字为97
			return m_ins->numToChar(97 + pos - 1);
		}
	}
private;
	getChar* m_ins;
}

三、一个适用装饰器模式的场景

生活中大家都会喝各种各样的饮料,以珍珠奶茶为例,计算一杯珍珠奶茶价格的场景就恰好试用装饰器模式。价目表如下:
饮品:基础奶茶 --- 10元加料:糖 		   --- 1元牛奶	   --- 2元珍珠	   --- 2元

例如一杯基础的奶茶10块钱,添加一份糖加1块钱,添加一份牛奶加2块钱,添加一份珍珠加2块钱,总计15元。下面我们使用装饰器模式来还原这样的场景。


四、使用装饰器模式实现奶茶价格的计算代码

1、代码功能设计

1、抽象饮料类Beverage,包含纯虚函数getprice获取奶茶价格接口
2、奶茶饮料类FruitBeverage ,继承抽象饮料类,实现getprice接口,返回一杯基础奶茶的价格
3、抽象装饰器类,继承奶茶饮料类FruitBeverage ,实现getprice接口
4、加料类SugarDec 、MilkDesc 、BubbleDesc ,继承FruitBeverage 实现getprice,返回各种加料的价格。

//抽象饮料类
	class Beverage
	{
	public:
		virtual int getprice() = 0; //获取价格
	public:
		virtual ~Beverage() {}
	};

	//奶茶饮料类
	class FruitBeverage : public Beverage
	{
	public:
		virtual int getprice()
		{
			return 10; //一杯单纯的奶茶饮料,售价为10元
		}
	};

	//抽象的装饰器类
	class Decorator :public Beverage
	{
	public:
		Decorator(Beverage* tmpbvg) :m_pbvg(tmpbvg) {} //构造函数
		virtual int getprice()
		{
			return m_pbvg->getprice();
		}
	private:
		Beverage* m_pbvg;
	};

	//具体的“砂糖”装饰器类
	class SugarDec :public Decorator
	{
	public:
		SugarDec(Beverage* tmpbvg) :Decorator(tmpbvg) {} //构造函数
		virtual int getprice()
		{
			return Decorator::getprice() + 1; //额外加多1元,要调用父类的getprice方法以把以往的价格增加进来
		}
	};

	//具体的“牛奶”装饰器类
	class MilkDesc :public Decorator
	{
	public:
		MilkDesc(Beverage* tmpbvg) :Decorator(tmpbvg) {} //构造函数
		virtual int getprice()
		{
			return Decorator::getprice() + 2; //额外加多2元,要调用父类的getprice方法以把以往的价格增加进来
		}
	};

	//具体的“珍珠”装饰器类
	class BubbleDesc :public Decorator
	{
	public:
		BubbleDesc(Beverage* tmpbvg) :Decorator(tmpbvg) {} //构造函数
		virtual int getprice()
		{
			return Decorator::getprice() + 2; //额外加多2元,要调用父类的getprice方法以把以往的价格增加进来
		}
	};

2、装饰器代码的使用

下面代码为使用装饰器模式代码计算珍珠奶茶价格的步骤,一开始创建了pfuit基础奶茶类,随后依次创建了添加珍珠的类,添加白糖的类,并且在每次创建新类对象时,都传入了上一个传入的对象。最后调用最后一个创建的pfruit_addbubb_addsugar 对象的getprice方法。由于装饰器类中的每一个实现,都保存了构造函数传入的类对象。所以当调用最后一个对象的getprice时,会递归的依次调用下去每一个对象的getprice方法,最终获取到一杯添加白糖和牛奶的奶茶价格。

    //创建一杯单纯的水果饮料,价格10元:
	Beverage* pfruit = new FruitBeverage();
	//向饮料中增加珍珠,价格多加了2元
	Decorator *pfruit_addbubb = new BubbleDesc(pfruit);
	//再向饮料中增加砂糖,价格又加多了1元
	Decorator* pfruit_addbubb_addsugar = new SugarDec(pfruit_addbubb);
	//输出最终的价格
	cout << "加了珍珠又加了砂糖的水果饮料最终价格是:" << \
	pfruit_addbubb_addsugar->getprice() << "元人民币" << endl;

	//释放资源
	delete pfruit_addbubb_addsugar;
	delete pfruit_addbubb;
	delete pfruit;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值