设计原则:类应该对扩展开发,对修改关闭。
装饰者可以在所委托被装饰者的行为之后加上自己的行为,以达到特定的目的。
装饰者模式:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
装饰者和被装饰者必须是一样的类型,也就是有相同的超类,因为装饰者新的行为必须能取代被装饰者。
假设在一家咖啡饮料店中,有饮料Decaf(低咖)、Tea(茶) 和可以添加的调料比如milk、mocha、sugar等,不同的用户可能会购买不同组合的饮料,并且在后续的营业中可能会出现新的饮料或者调料,现需要计算不同饮料的最终价格。
类图:
要让调料类可以引用到饮料类,做法:把饮料作为调料的构造器的参数,将饮料保存到调料的成员变量中。
注:1.其他饮料类和调料类的实现相同,所以项目内只实现了饮料Tea类和调料Milk类;
2.装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂;
实现如下:
beverage.h:
#ifndef BEVERAGE_H
#define BEVERAGE_H
#include <iostream>
#include <string>
using namespace std;
class Beverage {
public:
virtual string getDescription() = 0;
virtual double cost() = 0;
protected: // 只传给子类
string m_description;
};
#endif // BEVERAGE_H
tea.h:
#ifndef TEA_H
#define TEA_H
#include "beverage.h"
class Tea : public Beverage {
public:
Tea();
virtual string getDescription() override;
virtual double cost() override;
};
Tea::Tea()
{
m_description = "茶";
}
string Tea::getDescription()
{
return m_description;
}
double Tea::cost()
{
return 7.0;
}
#endif // TEA_H
condimentDecorator.h:
#ifndef CONDIMENTDECORATOR_H
#define CONDIMENTDECORATOR_H
#include "beverage.h"
class CondimentDecorator : public Beverage {
public:
virtual string getDescription() = 0;
};
#endif // CONDIMENTDECORATOR_H
milk.h:
#ifndef MILK_H
#define MILK_H
#include "condimentDecorator.h"
class Milk : public CondimentDecorator {
public:
Milk(Beverage* beverage);
virtual string getDescription() override;
virtual double cost() override;
private:
Beverage* m_beverage;
};
Milk::Milk(Beverage *beverage)
{
m_beverage = beverage;
}
string Milk::getDescription()
{
return m_beverage->getDescription() + " + 牛奶";
}
double Milk::cost()
{
return m_beverage->cost() + 2.0;
}
#endif // MILK_H
main.cpp:
/*
* 装饰者模式
*
* date:2023-9-7
*/
// milk: 2.0
// tea: 7.0
#include "tea.h"
#include "milk.h"
int main()
{
cout << "要一杯茶,加一份牛奶" << endl;
Beverage* beverage1 = new Tea();
Beverage* beverage2 = new Milk(beverage1);
cout << "订阅信息:" << beverage2->getDescription() <<
" ,花费金额:" << beverage2->cost() << endl << endl;
cout << "要一杯茶,加两份牛奶" << endl;
Beverage* beverage3 = new Tea();
Beverage* beverage4 = new Milk(beverage3);
Beverage* beverage5 = new Milk(beverage4);
cout << "订阅信息:" << beverage5->getDescription() <<
" ,花费金额:" << beverage5->cost() << endl;
}
运行结果: