天天看点

《Head First-设计模式》--装饰者模式C++实现

问题需求:

完成某咖啡店的订单系统,不同的咖啡(综合、深焙、低咖啡因,浓缩)有不同的价格,不同的调料(牛奶、摩卡、豆浆、奶泡)也有不同的价格。根据所加入的调料收 取不同的费用。显然不能用咖啡和调料组合的方法进行穷举订单类型,因为订单类型太多,而且以后还会有新的咖啡出现,也不利于维护和扩展。

装饰者模式:

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

设计思路:

1.装饰者和被装饰者应该为同一类型,即继承与同一个基类Breverage。

2.被装饰者继承基类,并完成接口实现。装饰者继承与一个装饰者基类,该基类与派生出的被装饰者类继承于同一个基类Breverage。装饰者基类的作用可以为装饰者增 加新的功能,而不需要修改Breverage(个人观点)。

3.一个被装饰者可以被多个装饰者装饰。

代码实现:

breverage.h

#ifndef BEVERAGE_H_
#define BEVERAGE_H_
#include<string>

using namespace std;

enum SIZE{ TALL = 0, GRANDE,VENTI};

class Beverage{
public:
	virtual string getDescription(){
		return description;
	}
	virtual double cost() = 0;;
	virtual SIZE getSize() = 0;
private:
	string description = "Unknown Beverage";
	SIZE cup_size;
};


#endif
           

被装饰者(咖啡)类Concrete.h

#ifndef CONCRETE_H_
#define CONCRETE_H_
#include"Beverage.h"

class Espresso :public Beverage{
public:
	~Espresso(){
	}
	Espresso(SIZE size){
		description = "Espresso";
		cup_size = size;
	}
	string getDescription()
	{
		return description;
	}
	double cost(){
		return 1.99;
	}

	void setSize(SIZE i){//设置咖啡杯的大小
		cup_size = i;
	}
	SIZE getSize(){//获得咖啡杯的大小
		return cup_size;
	}

private:
	string description;
	SIZE cup_size;
};

class HouseBlend :public Beverage{
public:
	~HouseBlend(){
	}
	HouseBlend(SIZE size){
		description = "House Blend Coffee";
		cup_size = size;
	}
	string getDescription()
	{
		return description;
	}
	double cost(){
		return 0.89;
	}
	void setSize(SIZE i){//设置咖啡杯的大小
		cup_size = i;
	}
	SIZE getSize(){//获得咖啡杯的大小
		return cup_size;
	}

private:
	string description;
	SIZE cup_size;
};

#endif
           

装饰者(调料)类 Condiment.h。增加了根据咖啡杯大小决定调料价格的功能

#ifndef CONDIMENT_H_
#define CONDIMENT_H_
#include"Beverage.h"

class Condiment :public Beverage{
public:
	virtual string getDescription()=0;
};

//摩卡
class Mocha :public Condiment{
public:
	Mocha(){
	}
	~Mocha(){
	}
	Mocha(Beverage *temp){
		this->coffee = temp;
	}
	string getDescription(){
		return coffee->getDescription() + ", Mocha";
	}
	SIZE getSize(){
		return coffee->getSize();
	}
	double cost(){//根据咖啡杯的大小决定加摩卡的价格
		double cost = coffee->cost();
		switch (getSize())
		{
		case TALL:
			cost += 0.20;
			break;
		case GRANDE:
			cost += 0.25;
			break;
		case VENTI:
			cost += 0.30;
			break;
		default:cout << "There is not this SIZE" << endl;
		}
		return cost;
	}
private:
	Beverage *coffee;
};

//豆浆
class Soy :public Condiment{
public:
	Soy(){}
	~Soy(){}
	Soy(Beverage *temp){
		this->coffee = temp;
	}
	string getDescription(){
		return coffee->getDescription() + ", Soy";
	}
	SIZE getSize(){
		return coffee->getSize();
	}
	double cost(){//根据咖啡杯的大小决定加豆浆的价格
		double cost = coffee->cost();
		switch (getSize())
		{
		case TALL:
			cost += 0.15;
			break;
		case GRANDE:
			cost += 0.20;
			break;
		case VENTI:
			cost += 0.25;
			break;
		default:cout << "There is not this SIZE" << endl;
		}
		return cost;
	}
private:
	Beverage *coffee;
};

//奶泡
class Whip :public Condiment{
public:
	Whip(){
	}
	~Whip(){
	}
	Whip(Beverage *temp){
		this->coffee = temp;
	}
	string getDescription(){
		return coffee->getDescription() + ", Soy";
	}
	SIZE getSize(){
		return coffee->getSize();
	}
	double cost(){
		double cost = coffee->cost();
		switch (getSize())
		{
		case TALL:
			cost += 0.10;
			break;
		case GRANDE:
			cost += 0.15;
			break;
		case VENTI:
			cost += 0.20;
			break;
		default:cout << "There is not this SIZE" << endl;
		}
		return cost;
	}
private:
	Beverage *coffee;
};

#endif
           

主函数main.cpp

#include<iostream>
#include"Beverage.h"
#include"Concrete.h"
#include"Condiment.h"

using namespace std;

int main()
{
	Beverage *beverage1 = new Espresso(TALL);
	
	cout << beverage1->getDescription() << " $" << beverage1->cost() << endl;

	Beverage *beverage2 = new HouseBlend(GRANDE);
	beverage2 = new Mocha(beverage2);
	beverage2 = new Mocha(beverage2);
	beverage2 = new Whip(beverage2);//用奶泡,2份摩卡“装饰”中杯的HouseBlend
	cout << beverage2->getDescription() << " $" << beverage2->cost() << endl;

	return 0;
}
           

运行结果:

《Head First-设计模式》--装饰者模式C++实现

总结:

1.装饰者和被装饰者必须是同一类型,这是装饰者模式的关键,在这里是利用继承达到“类型匹配”,而非继承行为。

2.装饰者和被装饰者进行组合时,就在装饰者中加入了新的行为,行为不是来自继而是来自组合。

3.依赖继承的行为,在编译时静态决定。利用组合,可以把装饰者混合使用,并且是在运行时决定行为。

感觉理解还不是很透彻,先写这些吧。

继续阅读