设计模式之Decorator

设计模式
学习笔记索引
Decorator(装饰)模式,可以动态地给一个对象添加一些额外的职能。为了更好地理解这个模式,我们将时间线拉回Bridge模式笔记的结尾。那时,白雪公主射出了充满魔法力量的一箭。如好莱坞大片一般,那支飞出的箭矢散发出各种你能想到的美丽光芒。当然,我不会告诉你那支箭华华丽丽地射偏了。因为我们这次更关心这绚烂的魔法效果。要说的是,时の魔导士在建立这个平行世界的时候,定义了一个所有可见物体的抽象类VisualObject:
 
1 class VisualObject {
2 public:    
3     virtual void show() = 0;    
4     // ... other ...
5 }
只要是出现在这个世界中,并能被世界之外的人们(比如说我们)看到的物体,都是它的子类。同时,必须实现show()方法。show定义了这个物体呈现给观众的样式。当然我们可以看到时の魔导士在创建箭矢时是如何偷懒的:
 
1 class Arrow : public VisualObject {
2 public:    
3     virtual void show() { cout << "你想它是什么样就是什么样。" << endl; }
4     // ... other ...
5 }
当然,这是不可行的。因为肯定有人会把Arrow想像成一个巨大的炮弹,甚至一头会飞的猪,以此来增强整个故事的动画性。但无论如何,当魔导士想要告诉大家,公主射出的箭矢是附着着冰霜效果的话,他必须明确地描述这支箭矢到底长什么样。如果偷懒到底,他大可以就创造个Arrow的子类IceArrow,只需多加个关于冰晶的描述就好了。
 
但是问题来了,既然可以附着魔法,箭矢就可以有更多更多的效果:附着火焰的,附着闪电的,长得更好看的,等等等等……如果每一个都用子类的话,必然会导致子类数目太多。况且,我们仅仅是希望给某个对象而不是整个类添加一些特效。同时别忘了我们还要考虑箭矢之外的可以附魔的东西。怎么办才好?时の魔导士采用了Decorator模式。
 
要点梳理
 
目的分类
对象结构型模式
范围准则
对象(该模式处理对象间的关系,这些关系在运行时刻是可以变化的,更具动态性)
主要功能
动态地给一个对象添加一些额外的职责。就增加功能来说, 它相比生成子类更为灵活。
适用情况
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
处理那些可以撤消的职责
当不能采用生成子类的方法进行扩充时。例如,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长
参与部分
Component:定义一个对象接口,可以给这些对象动态地添加职责
ConcreteComponent:定义一个对象,可以给这个对象添加一些职责
Decorator:维持一个指向Component对象的指针,并定义一个与Component接口一致的接口
ConcreteDecorator:向 组件添加职能
协作过程
Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作
UML图
 
 
示例分析 - 宛如大片中的魔法箭矢
 
 
 
请不要太在意上面这幅图到底是谁。为了能给箭矢(乃至更多物体)增加魔法效果,魔导士引入了ObjectDecorator类:
 
复制代码
 1 class ObjectDecorator : public VisualObject {
 2 public:
 3     ObjectDecorator(VisualObject *);
 4     
 5     virtual void show();
 6     // ... other ...
 7 private:
 8     VisualObject* _component;
 9 }
10 
11 void ObjectDecorator::show() {
12     _component->show();
13 }
复制代码
ObjectDecorator装饰由_component实例变量引用的VisualObject,这个变量在构造器中被初始化。同时,ObjectDecorator将show的请求转发给_component。我们将看到ObjectDecorator的子类之一MagicDecorator,它将能给可视化物件添加魔法的神奇效果:
 
复制代码
 1 class MagicDecorator : public ObjectDecorator {
 2 public:
 3     MagicDecorator(VisualObject *, int);
 4     virtual void show();
 5     // ... other ...
 6 private:
 7     int _magicType;    
 8     
 9     void addMagic(int);
10 }
11 
12 void MagicDecorator::show() {
13     ObjectDecorator::show();
14     addMagic(_magicType);
15 }
复制代码
类似的,我们也可以实现别的装饰类。我们接下来要把这个箭矢放到这个世界中去。假设World类(一个单例类)已经为此提供了一个add2Me操作:
 
1 void World::add2Me(VisualObject* obj) {
2     // ...
3     obj->show();
4     // ...
5 }
现在我们要让身处世界之外的人也看到一根箭矢,只需这么做:
 
1 Arrow* arrow = new Arrow();
2 World::getInstance()->add2Me(arrow);
那么此刻,正是展现电影特效各种神奇绚丽效果的时刻了。我们在将箭矢放入世界之前,先给它加上一层寒冰魔法的装饰:
 
1 #define ICEMAGIC 1
2 World::getInstance()->add2Me(new MagicDecorator(arrow, ICEMAGIC));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值