装饰者模式:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活
要点
1.继承属于扩展形式之一,但不见得是达到弹性设计的最佳方式
2.应该允许行为可以被扩展,而无须修改现有的代码
3.组合和委托可用于在运行时动态地加上新的行为
4.装饰者模式意味着一群装饰者类,这些类用来包装具体组件
5.装饰者类反映出被装饰的组件类型(事实上,他们具有相同的类型,都经过接口或继承实现)
6.装饰者被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的
7.你可以用无数个装饰者包装一个组件
8.装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型
9.装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得复杂
设计原则:类应该对扩展开放,对修改关闭。
[img]http://dl.iteye.com/upload/attachment/503759/c8a24a79-8efa-3951-a81f-d4235283df29.png[/img]
Beverage.h
#ifndef BEVERAGE_H
#define BEVERAGE_H
#include<string>
using namespace std;
enum SIZE{
SMALL,
MIDDLE,
BIG
};
class Beverage{
public:
explicit Beverage(SIZE size=MIDDLE):mDescription("unknown"),mSize(size){
}
virtual string getDescription()const{
return mDescription;
}
virtual double cost(){
return 0;
}
virtual SIZE getSize()const{
return mSize;
}
private:
string mDescription;
SIZE mSize;
};
#endif // BEVERAGE_H
CondimentDecorator.h
#ifndef CONDIMENTDECORATOR_H
#define CONDIMENTDECORATOR_H
#include"Beverage.h"
class CondimentDecorator:public Beverage{
public:
virtual string getDescription()const=0;
};
#endif // CONDIMENTDECORATOR_H
HouseBlend.h
#ifndef HOUSEBLEND_H
#define HOUSEBLEND_H
#include"Beverage.h"
class HouseBlend:public Beverage{
public:
explicit HouseBlend(SIZE size=MIDDLE)
:mDescription("HouseBlend"),mPrice(1.2),mSize(size){
}
virtual string getDescription()const{
return mDescription;
}
SIZE getSize()const{
return mSize;
}
virtual double cost(){
switch(getSize()){
case SMALL:
mPrice*=1;
break;
case MIDDLE:
mPrice*=1.2;
break;
case BIG:
mPrice*=1.5;
break;
}
return mPrice;
}
private:
string mDescription;
double mPrice;
SIZE mSize;
};
#endif // HOUSEBLEND_H
Milk.h
#ifndef MILK_H
#define MILK_H
#include"CondimentDecorator.h"
class Milk:public CondimentDecorator{
public:
explicit Milk(Beverage* bvg):mDescription("Mile"),mBvg(bvg),mPrice(0.5){
}
string getDescription()const{
return mBvg->getDescription()+","+mDescription;
}
double cost(){
switch(mBvg->getSize()){
case SMALL:
mPrice*=1;
break;
case MIDDLE:
mPrice*=1.2;
break;
case BIG:
mPrice*=1.5;
break;
}
return mBvg->cost()+mPrice;
}
private:
string mDescription;
Beverage* mBvg;
double mPrice;
};
#endif // MILK_H
Mocha.h
#ifndef MOCHA_H
#define MOCHA_H
#include"CondimentDecorator.h"
class Mocha:public CondimentDecorator{
public:
explicit Mocha(Beverage* bvg):mDescription("Mocha"),mBvg(bvg),mPrice(0.4){
}
string getDescription() const{
return mBvg->getDescription()+","+mDescription;
}
double cost(){
switch(mBvg->getSize()){
case SMALL:
mPrice*=1;
break;
case MIDDLE:
mPrice*=1.2;
break;
case BIG:
mPrice*=1.5;
break;
}
return mBvg->cost()+mPrice;
}
private:
string mDescription;
Beverage* mBvg;
double mPrice;
};
#endif // MOCHA_H
main.cpp
#include"Milk.h"
#include"HouseBlend.h"
#include"Mocha.h"
#include<iostream>
using namespace std;
int main()
{
Beverage* bvg1 = new HouseBlend(SMALL);//小杯
cout << bvg1->getDescription() << ":" << bvg1->cost() << endl;
bvg1 = new Milk(bvg1);//加了牛奶的饮料
cout << bvg1->getDescription() << ":" << bvg1->cost() << endl;
bvg1 = new Mocha(bvg1);//加了摩卡的饮料
cout << bvg1->getDescription() << ":" << bvg1->cost() << endl;
}
HouseBlend:1.2
HouseBlend,Mile:1.7
HouseBlend,Mile,Mocha:2.18
当系统需要新功能的时候,是向旧的类中添加新的代码.这些新加的代码通常装饰了原有类的核心职责或主要行为.它们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要.而装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有地,按顺序地使用装饰功能包装对象了
#include <iostream>
#include <string.h>
using namespace std;
class House
{
public:
House()
{
}
virtual ~House()
{
}
virtual void display()
{
cout << "房子:";
}
};
class FurnitureHouse:public House
{
public:
FurnitureHouse()
{
memset(mStr,0,sizeof(mStr));
strcpy(mStr,"床 ");
strcat(mStr,"凳子 ");
}
virtual ~FurnitureHouse(){}
virtual void display()
{
House::display();
cout << mStr;
}
public:
char mStr[128];
};
class TVHourse:public FurnitureHouse
{
public:
TVHourse(House* house)
{
mHouse = house;
strcpy(furStr,"电视 ");
}
void display()
{
mHouse->display();
cout << furStr;
}
private:
House* mHouse;
char furStr[32];
};
class AirConditionHouse:public FurnitureHouse
{
public:
AirConditionHouse(House* house)
{
mHouse = house;
strcpy(furStr,"空调 ");
}
void display()
{
mHouse->display();
cout << furStr;
}
private:
House* mHouse;
char furStr[32];
};
int main()
{
House* house = new FurnitureHouse;
cout << "House:" << house << endl;
house = new TVHourse(house);
house->display();
cout << "TVHouse:" << house << endl;
house = new AirConditionHouse(house);
house->display();
cout << "AirConditionHouse:" << house << endl;
}
House:0x93b4978
房子:床 凳子 电视 TVHouse:0x93b4a00
房子:床 凳子 电视 空调 AirConditionHouse:0x93b4ab0