Decorator - 装饰模式
1. 概述
若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性。如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继承这个类来产生一个新类—这建立在额外的代码上。
通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。如果 你希望改变一个已经初始化的对象的行为,你怎么办?或者,你希望继承许多类的行为,改怎么办?前一个,只能在于运行时完成,后者显然时可能的,但是可能会导致产生大量的不同的类—可怕的事情。
2. 问题
你如何组织你的代码使其可以容易的添加基本的或者一些很少用到的 特性,而不是直接不额外的代码写在你的类的内部?
3. 解决方案
装饰器模式: 动态地给一个对象添加一些额外的职责或者行为。就增加功能来说, Decorator模式相比生成子类更为灵活。
装饰器模式提供了改变子类的灵活方案。装饰器模式在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
当用于一组子类时,装饰器模式更加有用。如果你拥有一族子类(从一个父类派生而来),你需要在与子类独立使用情况下添加额外的特性,你可以使用装饰器模式,以避免代码重复和具体子类数量的增加。
4. 适用性
以下情况使用Decorator模式
1)• 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
2)• 处理那些可以撤消的职责。
3)• 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,
为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
5. 结构
UML图如下:

Component是定义一个对象接口,可以给这些对象动态地添加职责。
ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。
Decorator,装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。
至于ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。
要善于变通,如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。
同样道理,如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。
新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为
的需要。而装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为
时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。
代码如下:
Decorator.h

#ifndef _DECORATOR_H_
#define _DECORATOR_H_ //Component抽象类,定义该类对象的接口
class Component
{
public:
virtual ~Component();
virtual void Operation()=0;
protected:
Component();
}; //ConcreteDecorator:具体的Component对象,可以给该对象动态 添加职责
class ConcreteComponent:public Component
{
public:
ConcreteComponent();
~ConcreteComponent();
virtual void Operation();
}; //Decorator:装饰抽象类,继承自Component
class Decorator:public Component
{
public:
Decorator(Component* com);
void SetComponent(Component* com);
virtual ~Decorator();
virtual void Operation();
protected:
Component* _com;
}; //ConcreteDecorator就是具体的装饰对象之一,起到给Component添加职责的功能
class ConcreteDecoratorA:public Decorator
{
public:
ConcreteDecoratorA(Component* com);
~ConcreteDecoratorA();
virtual void Operation();
void AddBehavorA();
}; //ConcreteDecorator就是具体的装饰对象之二,起到给Component添加职责的功能
class ConcreteDecoratorB:public Decorator
{
public:
ConcreteDecoratorB(Component* com);
~ConcreteDecoratorB();
virtual void Operation();
void AddBehavorB();
}; //ConcreteDecorator就是具体的装饰对象之三,起到给Component添加职责的功能
class ConcreteDecoratorC:public Decorator
{
public:
ConcreteDecoratorC(Component* com);
~ConcreteDecoratorC();
virtual void Operation();
void AddBehavorC();
}; //ConcreteDecorator就是具体的装饰对象之四,起到给Component添加职责的功能
class ConcreteDecoratorD:public Decorator
{
public:
ConcreteDecoratorD(Component* com);
~ConcreteDecoratorD();
virtual void Operation();
void AddBehavorD();
}; //只添加一种装饰,则不用抽象出装饰基类
class DecoratorOnlyOne:public Component
{
public:
DecoratorOnlyOne(Component* com);
~DecoratorOnlyOne();
virtual void Operation();
void AddBehavor();
private:
Component* _com;
}; //如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。
//略
#endif

Decorator.cpp

#include "Decorator.h"
#include <iostream> using namespace std; Component::Component()
{} Component::~Component()
{
cout << "~Component" << endl;
} ConcreteComponent::ConcreteComponent()
{} ConcreteComponent::~ConcreteComponent()
{
cout << "~ConcreteComponent" << endl;
} void ConcreteComponent::Operation()
{
cout << "原职责:ConcreteComponent::Operation" << endl;
} Decorator::Decorator(Component* com)
{
this->_com = com;
} void Decorator::SetComponent(Component* com)
{
this->_com = com;
} Decorator::~Decorator()
{
cout << "~Decorator" << endl;
delete this->_com;
this->_com = NULL;
} void Decorator::Operation()
{} ConcreteDecoratorA::ConcreteDecoratorA(Component* com):Decorator(com)
{} ConcreteDecoratorA::~ConcreteDecoratorA()
{
cout << "~ConcreteDecoratorA" << endl;
} void ConcreteDecoratorA::Operation()
{
this->_com->Operation();
//附加职责A
this->AddBehavorA();
} void ConcreteDecoratorA::AddBehavorA()
{
cout << "附加职责A:ConcreteDecoratorA::AddBehavorA" << endl;
} ConcreteDecoratorB::ConcreteDecoratorB(Component* com):Decorator(com)
{} ConcreteDecoratorB::~ConcreteDecoratorB()
{
cout << "~ConcreteDecoratorB" << endl;
} void ConcreteDecoratorB::Operation()
{
this->_com->Operation();
//附加职责B
this->AddBehavorB();
} void ConcreteDecoratorB::AddBehavorB()
{
cout << "附加职责B:ConcreteDecoratorB::AddBehavorB" << endl;
} ConcreteDecoratorC::ConcreteDecoratorC(Component* com):Decorator(com)
{} ConcreteDecoratorC::~ConcreteDecoratorC()
{
cout << "~ConcreteDecoratorC" << endl;
} void ConcreteDecoratorC::Operation()
{
this->_com->Operation();
//附加职责C
this->AddBehavorC();
} void ConcreteDecoratorC::AddBehavorC()
{
cout << "附加职责C:ConcreteDecoratorC::AddBehavorC" << endl;
} ConcreteDecoratorD::ConcreteDecoratorD(Component* com):Decorator(com)
{} ConcreteDecoratorD::~ConcreteDecoratorD()
{
cout << "~ConcreteDecoratorD" << endl;
} void ConcreteDecoratorD::Operation()
{
this->_com->Operation();
//附加职责D
this->AddBehavorD();
} void ConcreteDecoratorD::AddBehavorD()
{
cout << "附加职责D:ConcreteDecoratorD::AddBehavorD" << endl;
} //**************只添加一种修饰******************
DecoratorOnlyOne::DecoratorOnlyOne(Component* com):_com(com)
{
} DecoratorOnlyOne::~DecoratorOnlyOne()
{
cout << "~DecoratorOnlyOne" << endl;
delete this->_com;
this->_com = NULL;
} void DecoratorOnlyOne::Operation()
{
this->_com->Operation();
this->AddBehavor();
} void DecoratorOnlyOne::AddBehavor()
{
cout << "附加唯一职责:DecoratorOnlyOne::AddBehavor" << endl;
}

main.cpp

#include "Decorator.h"
#include <iostream> using namespace std;
int main()
{
Component* pCom = new ConcreteComponent(); //要装饰的对象
Decorator* pDec = NULL;
pDec = new ConcreteDecoratorA(pCom); //给装饰对象附加职责A
pDec = new ConcreteDecoratorB(pDec); //给装饰对象附加职责B
pDec = new ConcreteDecoratorC(pDec); //给装饰对象附加职责C
pDec = new ConcreteDecoratorD(pDec); //给装饰对象附加职责D
pDec->Operation(); cout << "-------------------------------" << endl; //只添加一种修饰
Component* pCom1 = new ConcreteComponent();
DecoratorOnlyOne* pDec1 = new DecoratorOnlyOne(pCom1);
pDec1->Operation(); cout << "-------------------------------" << endl; delete pDec;
cout << "-------------------------------" << endl; delete pDec1; return 0;
}


总结
一般,当系统需要新功能的时候,是向旧的类中添加新的代码。这些新加的代码通常装饰了原有类的核心职责或主要行为,但这种做法的问题在于,它们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,并且新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。而装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。
那么装饰模式的优点有:1 把类中的装饰功能从类中搬移去除,这样可以简化原有的类,这样做更大的好处就是有效地把类的核心职责和装饰功能区分开了。而且可以去除相关类中重复的装饰逻辑。
Decorator - 装饰模式的更多相关文章
- C++设计模式-Decorator装饰模式
Decorator装饰模式作用:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活. UML图如下: Component是定义一个对象接口,可以给这些对象动态地添加职责. ...
- c++ 设计模式6 (Decorator 装饰模式)
4. “单一职责”类模式 在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任. 典型模式代表: Decorato ...
- 设计模式09: Decorator 装饰模式(结构型模式)
Decorator 装饰模式(结构型模式) 子类复子类,子类何其多加入我们需要为游戏中开发一种坦克,除了不同型号的坦克外,我们还希望在不同场合中为其增加以下一种多种功能:比如红外线夜视功能,比如水路两 ...
- 设计模式C++学习笔记之十三(Decorator装饰模式)
装饰模式,动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 13.1.解释 main(),老爸 ISchoolReport,成绩单接口 CFourt ...
- 设计模式学习笔记——Decorator装饰模式
装饰模式的作用或动机就是,尽量避免继承,而使用关联.原因是层层继承下来,内容会越来越多,有失控的危险.就扩展性而言,用关联比用继承好.所谓的关联,A使用了B,就叫A关联了B. Component 抽象 ...
- 设计模式学习之路——Decorator装饰模式(结构模式)
子类复子类,子类何其多 假如我们需要为游戏中开发一种坦克,除了各种不同型号的坦克外,我们还希望在不同场合中为其增加以下一种或多种功能:比如红外线夜视功能,比如水陆两栖功能,比如卫星定位功能等等. 动机 ...
- Decorator装饰模式
动态地给一个对象增加一些额外的职责.就增加功能而言,Decorator模式比生成子类更为灵活. ——<设计模式>GoF 作用:在不影响其他对象的情况下,以动态.透明的方式给单个对象添加职责 ...
- .NET设计模式(10):装饰模式(Decorator Pattern)(转)
概述 在软件系统中,有时候我们会使用继承来扩展对象的功能,但是由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性:并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多 ...
- .NET设计模式(10):装饰模式(Decorator Pattern)
.NET设计模式(10):装饰模式(Decorator Pattern) 装饰模式(Decorator Pattern) --.NET设计模式系列之十 年月..在....对于..由于使用装饰模 ...
随机推荐
- AT&T汇编语言——简单实例及工具演示
今天就来用详细实例代码来运用一下昨天所说的仅仅个工具的使用方法吧 这几个实例基本的目的是来熟悉一下汇编相关工具的使用方法及应用一下昨天刚说的汇编程序模板. 我们用到的工具主要有as,ld,gcc,gd ...
- GO语言基础之struct
结构struct 1. Go 中的struct与C中的struct非常相似,并且Go没有class 2. 使用 type <Name> struct{} 定义结构,名称遵循可见性规则(即首 ...
- Charles Proxy for Mac & Windows (4.1.3)破解激活工具
1.简介 2017年7月10日更新本博客,Charles已经更新到了4.1.3版本,并对应地给出破解jar包. Charles是一个Mac和Windows平台都可以使用的抓包工具,它的破解激活非常简单 ...
- python 两个队列进行对比
python 两个队列进行对比 list01 = [1,2,3,4] list02 = [1,3,5] for i01 in list01: is_in_02 = False for i02 in l ...
- PasswordlessAPI
passwordlessapiYOURLS允许API调用的老式的方法,使用用户名和密码参数(如果你的设置是私人的,很明显).如果担心将证书发送到野外,还可以使用秘密签名令牌进行API调用.签名的令牌你 ...
- NYOJ 113 字符串替换(C++STL解法)
字符串替换 时间限制:3000 ms | 内存限制:65535 KB 难度:2 描写叙述 编写一个程序实现将字符串中的全部"you"替换成"we& ...
- layer获取iframe内容
var layer1 = function() { layer.open({ type: 2, title: '标题', maxmin: false, area: ['780px', '600px'] ...
- PyQt5教程——组件 Ⅱ(八)
这部分的教程将会继续介绍PyQt5的组件.我们这节教程的内容将包括像素图(QPixmap),单行文本框(QLineEdit)和下拉列表框(QComboBox) 像素图(QPixmap) 像素图(QPi ...
- Android 如何将Canvas上绘制的内容保存成本地图片(转)
效果如下图所示 保存在sd卡上的文件为 手机上显示效果为: 1>>在Manifest文件中增加相应权限 <!-- 在SDCard中创建与删除文件权限 --> <uses- ...
- HDU 3974 Assign the task(dfs时间戳+线段树成段更新)
题意:给定点的上下级关系,规定假设给i分配任务a.那么他的全部下属.都停下手上的工作,開始做a. 操作 T x y 分配x任务y,C x询问x的当前任务: Sample Input 1 5 4 3 3 ...