1. 作用
装饰者模式是对继承的补充。怎么讲?
想想假如你想给某个类的方法加上一些功能,补充一下,但是又不能在原本的类上进行改动。首先想到的办法是继承这个类,重写这个需要加上某些功能的方法。过一段时间有需要加某些功能,你又继承刚刚那个类,又进行重写方法,几次下来,你继承层次就吓人了。
装饰者模式就是解决此类问题的,它避免了多次继承而实现改变某个方法的作用。
意图:动态的给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更加灵活。
2. UML类图
参与者:
- Component:定义一个对象接口,可以给这些对象动态地添加职责。
- ConcreteComponent:定义一个对象,可以给这个对象添加一些职责。
- Decorator:维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。
- ConcreteDecorator:向组件添加职责。
3. 实现
- 举例:相信很多人早餐都爱吃煎饼,去买煎饼一般都会加上各种东西,比如煎蛋,火腿肠,生菜等,想想这些加的东西不就是用来装饰煎饼的吗?加上这些东西之后煎饼依然还是煎饼。
代码:
#include <iostream>
#include <string>
using namespace std;
//抽象构件
//食物
class Food
{
public:
virtual string name() = 0;
virtual int cost() = 0;
};
//具体构件
//原味煎饼,啥都没加的
class Pancake :public Food
{
public:
virtual string name()
{
return "原味煎饼果子 ";
}
virtual int cost()
{
return 3;
}
};
//装饰者抽象角色,最重要的是持有Food
class ExtraFood :public Food
{
public:
ExtraFood(Food* food) :m_pFood(food){}
virtual string name()
{
return m_pFood->name();
}
virtual int cost()
{
return m_pFood->cost();
}
protected:
Food *m_pFood;
};
//具体装饰角色
//煎蛋
class Ege :public ExtraFood
{
public:
Ege(Food* food) :ExtraFood(food){}
virtual string name()
{
return m_pFood->name() + "鸡蛋 ";
}
virtual int cost()
{
return m_pFood->cost() + 1;
}
};
//具体装饰角色
//火腿
class Ham :public ExtraFood
{
public:
Ham(Food* food) :ExtraFood(food){}
virtual string name()
{
return m_pFood->name() + "火腿 ";
}
virtual int cost()
{
return m_pFood->cost() + 2;
}
};
//具体装饰角色
//生菜
class Lettuce :public ExtraFood
{
public:
Lettuce(Food* food) :ExtraFood(food){}
virtual string name()
{
return m_pFood->name() + "生菜 ";
}
virtual int cost()
{
return m_pFood->cost() + 1;
}
};
//买煎饼果子了
int main()
{
//先来一个原味的煎饼
Food * pancake = new Pancake;
cout << pancake->name() << "价格是" << pancake->cost() << "元" << endl;
//加个蛋
pancake = new Ege(pancake);
cout << pancake->name() << "价格是" << pancake->cost() << "元" << endl;
//加个火腿肠
pancake = new Ham(pancake);
cout << pancake->name() << "价格是" << pancake->cost() << "元" << endl;
//加生菜
pancake = new Lettuce(pancake);
cout << pancake->name() << "价格是" << pancake->cost() << "元" << endl;
//资源释放.......
return 0;
}
结果:
原味煎饼果子 价格是3元
原味煎饼果子 鸡蛋 价格是4元
原味煎饼果子 鸡蛋 火腿 价格是6元
原味煎饼果子 鸡蛋 火腿 生菜 价格是7元
请按任意键继续. . .
4. 优缺点
- 优点:
比继承更加灵活,很容易重复添加或改变一个特性。 - 缺点:
多层装饰比较复杂,层次越多,小类越多,越里层的装饰需要改动,越复杂。
装饰模式是针对抽象构建(Component)类型编程。但是,如果要针对具体构件(ConcreteComponent)编程,应该重新思考应用架构,以及装饰者是否合适。当然也可改变 Component 接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择
5. 适用场景
需要扩展一个类的功能,或给一个类增加附加功能。
需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
6. 总结
装饰者模式是继承之外可以改变一个方法的模式,值得注意的是当具体装饰者较时少,可以考虑取消装饰者抽象类。