装饰器模式是非常特殊的一个模式,它既用到了继承也用到了组合,而继承和组合也是设计模式中常用的手法。
装饰器模式的定义:是在不比改变原来类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
用现实中的列子来类比,例如:我们喝奶茶或者果汁的时候,可以添加不同的辅料,椰果、珍珠、冰块、糖等等。通过这些原料我们可以自己组合成自己喜爱的饮料。
UML结构图如下:
下面我用伪码来表述上面的例子。
//饮料类
class Drinks
{
public:
virtual int Price() = 0;//饮料的价格
};
//奶茶类
class MilkyTea : public Drinks
{
public:
int Price(){
return 10; //单独的奶茶卖10块钱一杯
}
};
//果汁类
class FruitJuice: public Drinks
{
public:
int Price(){
return 8; //单独的果汁卖8块钱一杯
}
};
//奶茶类和果汁类都继承自饮料类--这里就是装饰器模式中所说的“原来类文件和使用继承的情况”。
//我们需要的是“动态地扩展一个对象的功能”,这里就是扩展奶茶类和果汁类的功能
//辅料类,就是装饰类Decorator,这里我们理解添加的辅料就是这些饮料的装饰
//这个装饰类是整个装饰器模式的精华,既有继承也有组合
class Decorator: public Drinks//既有继承
{
protected:
Drinks *m_pDrinks;//也有组合
public:
Decorator(Drinks *pDrinks) : m_pDrinks(pDrinks) {}
virtual int Price(){
//这里就可以加一些我们自己的操作了
return pDrinks->Price();
}
};
//具体的辅料(装饰)
//椰果
class Coconut : public Decorator
{
public:
Coconut(Drinks *pDrinks) : Decorator(pDrinks) {}
int Price(){
return m_pDrinks->Price() + 2;//加椰果的饮料就要在原来的基础上加2块钱
}
}
//珍珠
class Pearl: public Decorator
{
public:
Pearl(Drinks *pDrinks) : Decorator(pDrinks) {}
int Price(){
return m_pDrinks->Price() + 3;//加珍珠的饮料就要在原来的基础上加3块钱
}
}
//应用
int main()
{
//来一杯奶茶
Drinks *pDrinks = new MilkyTea();
std::cout<<"Price ="<<pDrinks->Price()<<std::endl;
//来一杯奶茶+椰果
Decorator *pDecoratorCoconut = new Coconut(pDrinks);
std::cout<<"Price ="<<pDecoratorCoconut->Price()<<std::endl;
//来一杯奶茶+珍珠
Decorator *pDecoratorPearl = new Pearl(pDrinks);
std::cout<<"Price ="<<pDecoratorPearl->Price()<<std::endl;
//果汁同理这里就不写了
}
现在返回那张UML图我们再来看:
结合到我们的例子和装饰器模式的定义,其中稳定的部分就是我们的饮料类以及奶茶类和果汁类,这个是我们不能动的。另外我们增加的装饰器类也是稳定的,因为在这个类中我们并没有具体的指向某一种饮料,而是指向了它们的父类。变化的部分是从饮料类可能再继承出来的新的类,以及我们后面增加的具体的装饰(这里就是各种辅料:椰果、珍珠等)。 我们是通过继承和组合的方式来动态扩展饮料类对象的功能。
最后,如果理解的有偏差,还请指出!