一、描述
装饰模式,动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
问题:
在 OO 设计和开发过程,可能会经常遇到以下的情况:我们需要为一个已经定义好的类添加新的职责(操作),通常的情况我们会给定义一个新类继承自定义好的类,这样会带来一个问题(将在本模式的讨论中给出)。通过继承的方式解决这样的情况还带来了系统的复杂性,因为继承的深度会变得很深。
而 Decorator 提供了一种给类增加职责的方法,不是通过继承实现的,而是通过组合。有关这些内容在讨论中进一步阐述。
模式选择:
Decorator 模式典型的结构图为:
图 2-1:Decorator Pattern 结构图在结构图
ConcreteComponent 和 Decorator 需要有同样的接口,因此ConcreteComponent 和 Decorator 有着一个共同的父类。这里有人会问,让 Decorator 直接维护一个指向 ConcreteComponent 引用(指针)不就可以达到同样的效果,答案是肯定并且是否定的。肯定的是你可以通过这种方式实现,否定的是你不要用这种方式实现,因为通过这种方式你就只能为这个特定的 ConcreteComponent 提供修饰操作了,当有了一个新的 ConcreteComponent 你又要去新建一个 Decorator 来实现。
但是通过结构图中的ConcreteComponent 和 Decorator 有一个公共基类,就可以利用 OO 中多态的思想来实现只要是 Component 型别的对象都可以提供修饰操作的类,这种情况下你就算新建了 100 个Component 型别的类 ConcreteComponent,也都可以由 Decorator 一个类搞定。
这也正是Decorator 模式的关键和威力所在了。
当然如果你只用给 Component 型别类添加一种修饰,则 Decorator 这个基类就不是很必要了。
二、实例
就说说"我"上小学的的糗事吧。我上小学的时候学习成绩非常的差,班级上 40 多个同学,我基本上都是在排名 45 名以后,按照老师给我的定义就是“不是读书的料”,但是我老爸管的很严格,明知道我不是这块料,还是往赶鸭子上架,每次考试完毕我都是战战兢兢的,“竹笋炒肉”是肯定少不了的,能少点就少点吧,肉可是自己的呀。四年级期末考试考完,学校出来个很损的招儿(这招儿现在很流行的),打印出成绩单,要家长签字,然后才能上五年级,我那个恐惧呀,不过也就是几秒钟的时间,玩起来什么都忘记了。当时,我的成绩(语文 62 数学65 体育 98 自然 63),
你要知道在小学低于 90 分基本上就是中下等了,唉,爱学习的人太多了!怎么着,那我把这个成绩单给老爸看看?
就这成绩还要我签字?!老爸就开始找笤帚,我的屁股已经做好了准备,肌肉要绷紧,要不那个太疼了!哈哈,幸运的是,这个不是当时的真实情况,我没有直接把成绩单交给老爸,而是在交给他之前做了点技术工作,我要把成绩单封装一下,封装分类两步走:
第一步:跟老爸说各个科目的最高分,语文最高是 75,数学是 78,自然是 80,然老爸觉的我成绩与最高分数相差不多,这个是实情,但是不知道是什么原因,反正期末考试都考的不怎么样,但是基本上都集中在 70 分以上,我这 60 多分基本上还是垫底的角色;
第二步:在老爸看成绩单后,告诉他我是排名第 38 名,全班,这个也是实情,为啥呢?有将近十个同学退学了!这个情况我是不说的。不知道是不是当时第一次发成绩单,学校没有考虑清楚,没有写上总共有多少同学,排名第几名等等,反正是被我钻了个空子。类图如下:
ISchoolReport,成绩单接口
CFourthGradeSchoolReport,四年级成绩单
ReportDecorator,成绩单装饰器基类
HighScoreDecorator,最高分装饰器
SortDecorator,班级排名装饰器
说明:对“四年级成绩单”进行装饰,ReportDecorator必然有一个private变量指向ISchoolReport。
#ifndef Decorator_ISchoolReport_h
#define Decorator_ISchoolReport_h
#include<iostream>
using std::string;
class ISchoolReport
{
public:
ISchoolReport(void){}
virtual ~ISchoolReport(void){}
virtual void Report() = 0;
virtual void Sign(string name) = 0;
};
#endif
四年级成绩单:FouthGradeSchoolReport
#ifndef __Decorator__FouthGradeSchoolReport__
#define __Decorator__FouthGradeSchoolReport__
#include <iostream>
#include "ISchoolReport.h"
class CFouthGradeSchoolReport:public ISchoolReport
{
public:
CFouthGradeSchoolReport(void);
~CFouthGradeSchoolReport(void);
void Report();
void Sign(string name);
};
#endif /* defined(__Decorator__FouthGradeSchoolReport__) */
FouthGradeSchoolReport.cpp
#include "FouthGradeSchoolReport.h"
using std::cout;
using std::endl;
using std::string;
CFouthGradeSchoolReport::CFouthGradeSchoolReport(void)
{
}
CFouthGradeSchoolReport::~CFouthGradeSchoolReport(void)
{
}
void CFouthGradeSchoolReport::Report()
{
cout << "尊敬的XXX家长:" << endl;
cout << "......" << endl;
cout << "语文62 数学65 体育98 自然63" << endl;
cout << "......" << endl;
cout << " 家长签名:" << endl;
}
void CFouthGradeSchoolReport::Sign(string name)
{
cout << "家长签名为:" << name.c_str() << endl;
}
成绩单装饰器基类:ReportDecorator类
#ifndef __Decorator__ReportDecorator__
#define __Decorator__ReportDecorator__
#include <iostream>
#include "ISchoolReport.h"
class CReportDecorator:public ISchoolReport
{
public:
CReportDecorator(ISchoolReport *psr);
virtual ~CReportDecorator(void);
void Report();
void Sign(string name);
private:
ISchoolReport *m_pSchoolReport;
};
#endif /* defined(__Decorator__ReportDecorator__) */
ReportDecorator.cpp
#include "ReportDecorator.h"
using std::string;
CReportDecorator::CReportDecorator(ISchoolReport *psr)
{
this->m_pSchoolReport = psr;
}
CReportDecorator::~CReportDecorator(void)
{
}
void CReportDecorator::Report()
{
this->m_pSchoolReport->Report();
}
void CReportDecorator::Sign(string name)
{
this->m_pSchoolReport->Sign(name);
}
最高分装饰器:HighScoreDecorator
#ifndef __Decorator__HighScoreDecorator__
#define __Decorator__HighScoreDecorator__
#include <iostream>
#include "ReportDecorator.h"
#include "ISchoolReport.h"
class CHighScoreDecorator:public CReportDecorator
{
public:
CHighScoreDecorator(ISchoolReport *psr);
~CHighScoreDecorator(void);
void Report();
private:
void ReportHighScore();
};
#endif /* defined(__Decorator__HighScoreDecorator__) */
HighScoreDecorator.cpp
#include "HighScoreDecorator.h"
using std::cout;
using std::endl;
CHighScoreDecorator::CHighScoreDecorator(ISchoolReport *psr):CReportDecorator(psr)
{
}
CHighScoreDecorator::~CHighScoreDecorator(void)
{
}
void CHighScoreDecorator::Report()
{
this->ReportHighScore();
this->CReportDecorator::Report();
}
void CHighScoreDecorator::ReportHighScore()
{
cout << "这次考试语文最高是75, 数学是78, 自然是80" << endl;
}
班级排名装饰器:SortDecorator类
#ifndef __Decorator__SortDecorator__
#define __Decorator__SortDecorator__
#include <iostream>
#include "ReportDecorator.h"
#include "ISchoolReport.h"
class CSortDecorator:public CReportDecorator {
public:
CSortDecorator(ISchoolReport *psr);
~CSortDecorator(void);
void Report();
private:
void ReportSort();
};
#endif /* defined(__Decorator__SortDecorator__) */
SortDecorator.cpp
#include "SortDecorator.h"
using std::cout;
using std::endl;
CSortDecorator::CSortDecorator( ISchoolReport *psr ) : CReportDecorator(psr)
{
}
CSortDecorator::~CSortDecorator(void)
{
}
void CSortDecorator::ReportSort()
{
cout << "我是排名第38名..." << endl;
}
void CSortDecorator::Report()
{
this->CReportDecorator::Report();
this->ReportSort();
}
主程序:main
#include <stdio.h>
#include "ISchoolReport.h"
#include "FouthGradeSchoolReport.h"
#include "FouthGradeSchoolReport.h"
#include "HighScoreDecorator.h"
#include "SortDecorator.h"
#include <iostream>
using std::cout;
using std::endl;
void DoIt()
{
ISchoolReport *psr = new CFouthGradeSchoolReport();
psr->Report();//
psr->Sign("老三");//很开心,就签字了
delete psr;
}
void DoNew()
{
cout << "----------分部分进行装饰----------" << endl;
ISchoolReport *psr = new CFouthGradeSchoolReport();//原装成绩单
ISchoolReport *pssr = new CSortDecorator(psr);//又加了成绩排名的说明
ISchoolReport *phsr = new CHighScoreDecorator(pssr);//加了最高分说明的成绩单
phsr->Report();//看成绩单
phsr->Sign("老三");//很开心,就签字了
//先装饰哪个不重要,顺序已经在装饰内部确定好,但一定要调用最后一个装饰器的接口。
//ISchoolReport *phsr = new CHighScoreDecorator(psr);//加了最高分说明的成绩单
//ISchoolReport *pssr = new CSortDecorator(phsr);//又加了成绩排名的说明
//pssr->Report();//看成绩单
//pssr->Sign("老三");//很开心,就签字了
delete pssr;
delete phsr;
delete psr;
}
int main(int argc, const char * argv[])
{
//在装饰之前,可以用继承的办法,来进行简单的修饰
DoIt();
//但如果需要修饰的项目太多呢?或者装饰的项目不是固定的,继承显然会变得更复杂
DoNew();
// insert code here...
printf("Hello, World!\n");
return 0;
}
结果如下:
参考文献:《设计模式之禅》,《GoF_23种设计模式解析》
参考博客:http://www.cnblogs.com/wanggary/archive/2011/04/18/2020254.htm