- 装饰者模式
动态地将责任附加到对象上。若要扩展功能,装饰者提供比继承更有弹性的替代方案。
- 应用分析——对象的功能扩展
对象的功能扩展,最简单的方式就是继承,但是几种不同的功能有不同的组合时,将会产生许许多多的类,这样不利于管理。采用装饰者模式,让装饰者与实际对象有相同的接口(继承同一抽象类),通过组合或委托的方式引用被装饰对象,然后对被装饰对象进行动态扩展,可以获得更大的灵活性。
- 实例分析——星巴克有各种咖啡:HouseBlend、DarkRoast、Decaf、Espresso,客户购买时,可以要求加入各种调料,如:SteamedMilk、Soy、Mocha等等,星巴克会根据不同的调料进行收费,如果考虑用继承实现,那么类数将会爆发性增长,如果考虑使用标记变量,这可能是一个解决方案,但是不利于扩展,用装饰者模式,可以巧妙解决这一问题。
- 代码分析
//Component.h
//公共接口
#ifndef COMPONENT_H
#define COMPONENT_H
#include <string>
class Component//被装饰对象和装饰者公共的接口
{
protected:
std::string desc;
public:
virtual std::string getdesc()
{
return desc;
}
virtual double cost()=0;
virtual ~Component(){}
};
#endif
//ConcreteComponent.h
//被装饰者
#ifndef CONCRETECOMPONENT_H
#define CONCRETECOMPONENT_H
#include "Component.h"
//两种不同的咖啡
class HouseBlend:public Component
{
public:
HouseBlend()
{
desc="HouseBlend";
}
double cost()
{
return 10.0;
}
};
class DarkRoast:public Component
{
public:
DarkRoast()
{
desc="DarkRoast";
}
double cost()
{
return 20.0;
}
};
#endif
//Decorator.h
//装饰者
#ifndef DECORATOR_H
#define DECORATOR_H
#include "Component.h"
//两种调料
class Milk:public Component
{
private:
Component *ptrCom;//被装饰者
public:
Milk(Component *ptrCom)
{
this->ptrCom=ptrCom;
}
std::string getdesc()
{
return ptrCom->getdesc()+", Milk";
}
double cost()
{
return ptrCom->cost()+5.0;
}
};
class Mocha:public Component
{
private:
Component *ptrCom;
public:
Mocha(Component *ptrCom)
{
this->ptrCom=ptrCom;
}
std::string getdesc()
{
return ptrCom->getdesc()+", Mocha";
}
double cost()
{
return ptrCom->cost()+15.0;
}
};
#endif
//main.cpp
//测试程序
#include <iostream>
#include "Decorator.h"
#include "ConcreteComponent.h"
#define print(x) std::cout<<x->getdesc()<<": $"<<x->cost()<<std::endl
int main()
{
Component *HB=new HouseBlend();
print(HB);
Component *DR=new DarkRoast();
print(DR);
Component *HB_Milk=new Milk(HB);
print(HB_Milk);
Component *HB_Milk_M=new Mocha(HB_Milk);
print(HB_Milk_M);
Component *DR_M=new Mocha(DR);
print(DR_M);
delete HB;
delete HB_Milk;
delete HB_Milk_M;
delete DR;
delete DR_M;
return 0;
}