Decorator模式,可以不改变原有类,或者凡索的继承就可以改变其行为。不会破坏原有接口。
我觉得decorator是最优雅的一个模式。设计模式中的小贵妇,小喜欢。
还是那个经典的咖啡加牛奶,糖的问题。其实牛奶咖啡不是咖啡,也不是牛奶。只是一个组合体,所以用继承等来解决从概念上就有点说不通。何况还会带来乘积关系的子类膨胀。直接写代码吧:
/**
* @file test_decorator.h
* @author itegel
* @date 2014/04/02 17:10:16
* @brief
*
**/
#ifndef __TEST_DECORATOR_H_
#define __TEST_DECORATOR_H_
#include <iostream>
//component
class Component{
public:
Component(){}
virtual void Describe() = 0;
};
// concrete component
class Coffee : public Component{
public:
Coffee(){}
virtual void Describe() {
std::cout<<"I am just one cup of coffee!"<<std::endl;
}
};
// concrete component
class Tea : public Component{
public:
Tea(){}
virtual void Describe() {
std::cout<<"I am just one cup of tea!"<<std::endl;
}
};
//milk
class MilkComponent : public Component{
public:
MilkComponent(Component * component){
component_ = component;
}
virtual void Describe() {
component_->Describe();
std::cout<<"I am added milk!"<<std::endl;
}
private:
Component * component_;
};
//sugar
class SugarComponent : public Component{
public:
SugarComponent(Component * component){
component_ = component;
}
virtual void Describe() {
component_->Describe();
std::cout<<"I am added sugar!"<<std::endl;
}
private:
Component * component_;
};
#endif //__TEST_DECORATOR_H_
/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
/**
* @file test_decorator.cpp
* @author itegel
* @date 2014/04/02 17:22:47
* @brief
*
**/
#include "test_decorator.h"
int main(){
std::cout<<"milk coffee:"<<std::endl;
Coffee coffee;
MilkComponent milk_coffee(&coffee);
milk_coffee.Describe();
std::cout<<std::endl<<"milk, sugar tea:"<<std::endl;
Tea tea;
SugarComponent sugar_tea(&tea);
MilkComponent milk_sugar_tea(&sugar_tea);
milk_sugar_tea.Describe();
return 0;
}
输出:
milk coffee:
I am just one cup of coffee!
I am added milk!
milk, sugar tea:
I am just one cup of tea!
I am added sugar!
I am added milk!
可以先看看client代码,跟人们的正常认识和真是生活更贴切。我先磨一杯咖啡,加点牛奶。如果觉得苦了还可以再加一点糖....
而且加糖,加牛奶等这些还可以累加,跟顺序也无关。
我想他可能存在的问题是,如果想增加个接口,那么被装饰的类和装饰类都需要相应修改。不过装饰类一般也不会很多。用这一点点代价换取子类膨胀等问题,我觉得很多时候都是值当的。而如果只需要一个装饰类的时候,该模式也可以简单退化为直接从父类继承出响应的装饰类即可。
我觉得装饰模式比较惊喜的特点是,可以用任何顺序叠加不同装饰。就像刷墙漆,可以一层一层刷很多遍。