【设计模式】Head First 设计模式——装饰者模式 C++实现

设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。

设计思想

动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

装饰类继承自超类,继承是为了有正确的类型,而非继承超类的行为。

业务场景

假定你需要给蜜雪冰城设计一套售卖系统。他们家所有的饮料假设只有描述和价格两种属性,你可能又会想到用继承去解决:先抽象一个奶茶父类,然后每种奶茶都继承该父类并实现各自的display和cost方法。

你很快就会发现这么做有很多麻烦:首先,这家奶茶店所有的奶茶种类加一起数量可能有几十种数百种,这也就意味着你的子类会有很多很多;其次,这么设计似乎并不符合实际的业务场景,人们点奶茶的时候并不是一成不变的,有的不要珍珠,有的双倍糖等等,加的调料和份数也不一样,那么最后如何描述这杯奶茶以及计算其价格就成了问题。

代码案例

C++ 复制代码
#include<iostream>
#i#include<iostream>
#include<vector>
#include<algorithm>
#include <string>
#include <memory>
 
//饮料抽象类
class Beverage {
public:
	virtual ~Beverage() {};
	virtual std::string getDescription() = 0;
	virtual double cost() = 0;
protected:
	std::string description;
	
};
//调料装饰者类
class Condimentecorator :public Beverage {
public:
	virtual ~Condimentecorator() {};
	virtual std::string getDescription() = 0;
};
 
//espresso 饮料类
class Espresso :public Beverage {
public:
	Espresso() :Beverage()
	{
		description = "Espresso";
	}
	std::string getDescription() { return description; }
	double cost() 
	{
		return 1.99;
	}
};
 
//houseblend 饮料类
class HouseBlend :public Beverage {
public:
	HouseBlend() :Beverage()
	{
		description = "HouseBlend";
	}
	std::string getDescription() { return description; }
	double cost() 
	{
		return 0.89;
	}
};
 
//DarkRoast 饮料类
class DarkRoast :public Beverage {
public:
	DarkRoast() :Beverage()
	{
		description = "DarkRoast";
	}
	std::string getDescription() { return description; }
	double cost() 
	{
		return 0.99;
	}
};
 
//Decat 饮料类
class Decat :public Beverage {
public:
	Decat() :Beverage()
	{
		description = "Decat";
	}
	std::string getDescription() { return description; }
	double cost()
	{
		return 1.05;
	}
};
 
//Mocha调料装饰者
class Mocha :public Condimentecorator {
 
public:
	Mocha(std::shared_ptr<Beverage> be) :Condimentecorator(), beverage(be) {}
	std::string getDescription() 
	{
		return (beverage->getDescription() + " Mocha");
	}
	double cost()
	{
		return 0.2 + beverage->cost();
	}
 
public:
	std::shared_ptr<Beverage> beverage;
};
 
//Soy调料装饰者
class Soy :public Condimentecorator {
public:
	Soy(std::shared_ptr<Beverage> be):Condimentecorator(),beverage(be){}
	std::string getDescription()
	{
		return (beverage->getDescription() + " Soy");
	}
	double cost()
	{
		return 0.15 + beverage->cost();
	}
public:
	std::shared_ptr<Beverage> beverage;
};
 
//Whip调料装饰者
class Whip :public Condimentecorator {
public:
	Whip(std::shared_ptr<Beverage> be) :Condimentecorator(), beverage(be) {}
	std::string getDescription()
	{
		return (beverage->getDescription() + " Whip");
	}
	double cost()
	{
		return 0.10 + beverage->cost();
	}
public:
	std::shared_ptr<Beverage> beverage;
};
 
int main()
{
	std::shared_ptr<Beverage> beverage = std::make_shared<Espresso>();
	std::cout << beverage->getDescription()<<" costs: "<<beverage->cost() << std::endl;
 
	std::shared_ptr<Beverage> beverage2 = std::make_shared<DarkRoast>();
	std::cout << beverage2->getDescription() << " costs: " << beverage2->cost() << std::endl;
 
    beverage2 = std::make_shared<Mocha>(beverage2);
	std::cout << beverage2->getDescription() << " costs: " << beverage2->cost() << std::endl;
 
    beverage2 = std::make_shared<Mocha>(beverage2);
	std::cout << beverage2->getDescription() << " costs: " << beverage2->cost() << std::endl;
 
	beverage2 = std::make_shared<Whip>(beverage2);
	std::cout << beverage2->getDescription() << " costs: " << beverage2->cost() << std::endl;

	auto it = std::make_shared<Whip>(beverage2);
	std::cout << it->cost() << " " << it->getDescription() << std::endl;
	std::cout << it->beverage->cost() << " " << it->beverage->getDescription() << std::endl;

	return 0;
}
相关推荐
1024奇点6 小时前
【仓颉语言入门 · 第二篇 第 22 课】
开发语言·ide·开源
Warren2Lynch7 小时前
C4 模型详解:利用 Visual Paradigm 可视化软件架构的综合指南
开发语言·uml
FlightYe8 小时前
视界原理之3D视频(四):裸眼、眼镜和头显
android·linux·c++·3d·ffmpeg·音视频
Knight_AL8 小时前
Java 文件下载时文件名中的 `#` 被转换成 `%23`?一次 URL 编码与解码问题排查
java·开发语言
FRing038 小时前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2
by209999 小时前
C++ 智能指针的所有权与使用
开发语言·c++·经验分享
砚底藏山河9 小时前
python量化自定义周期 K 线合成
java·开发语言·数据库·python·金融
IT召唤狮9 小时前
开源企业级零信任项目Pangolin,零信任能挡住PHP核弹漏洞吗?
开发语言·开源·php
知已难寻9 小时前
03 · OpenStack的计算管理 Nova
运维·服务器·开发语言·云原生·云计算·openstack·开源软件
Rover Ramble9 小时前
C++ 用互斥锁实现读写锁
开发语言·c++