装饰模式(Decorator Pattern)结构型模式.
设计原则:类应该对扩展开放,对修改关闭.
例子:用调料来装饰饮料。比如说顾客想要摩卡和奶泡深焙咖啡,那么要做的是:
1.拿一个深焙咖啡(DarkRoast)对象
2.以摩卡(Mocha)对象去装饰它
3.以奶泡(Whip)对象去装饰它
4.调用cost()方法,并依赖委托(delegate)将调料的价格加上去。
装饰着和被装饰者对象有相同的超类型(关键)。通过继承达到类型匹配而不是获取行为。可以用一个或多个装饰者包装一个对象。
定义:装饰者模式动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
HeadFirst中咖啡店的类图如下:
C++实现代码如下:
Component.h头文件:
#ifndef _COMPONENT_H_
#define _COMPONENT_H_
#include <string>
using namespace std;
//饮料抽象类
class Beverage
{
public:
virtual string getDescription();
virtual double cost()=0;
protected:
string description;
};
//抽象装饰者调料类
class CondimentDecorator:public Beverage
{
public:
virtual string getDescription()=0;
};
//具体饮料,被装饰的对象
class Espresso:public Beverage
{
public:
Espresso();
~Espresso();
double cost();
};
class HouseBlend:public Beverage
{
public:
HouseBlend();
~HouseBlend();
double cost();
};
//具体调料类
class Mocha:public CondimentDecorator
{
public:
Mocha(Beverage *beverage);
string getDescription();
double cost();
private:
Beverage *beverage; //记录被装饰者,即饮料
};
#endif
Component.CPP源文件
#include "Component.h"
#include <iostream>
#include <string>
using namespace std;
string Beverage::getDescription()
{
return description;
}
//被装饰者类
HouseBlend::HouseBlend()
{
description="House Blend Coffee";
}
HouseBlend::~HouseBlend()
{
cout<<"~HouseBlend()"<<endl;
}
double HouseBlend::cost()
{
return 0.89;
}
Espresso::Espresso()
{
description="Espresso";
}
Espresso::~Espresso()
{
cout<<"~Espresso()"<<endl;
}
double Espresso::cost()
{
return 1.99;
}
//装饰者类
Mocha::Mocha(Beverage *beverage)
{
this->beverage=beverage;
}
string Mocha::getDescription()
{
return beverage->getDescription()+",Mocha";
}
double Mocha::cost()
{
return 0.20+beverage->cost();
}
主函数main.CPP
#include "Component.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
//订一杯Espresso,不需要调料,并打印出描述及其价格
Beverage *beverage=new Espresso();
cout<<beverage->getDescription()<<" $"<<beverage->cost()<<endl;
//订一杯HouseBlend并加入Mocha调料,打印出描述及其价格
Beverage *beverage2=new HouseBlend();
beverage2=new Mocha(beverage2); //用Mocha去装饰HouseBlend
cout<<beverage2->getDescription()<<" $"<<beverage2->cost()<<endl;
return 0;
}