装饰模式就是将添加的附加功能分别放在单独的类中,并在这个类中包含它要装饰的对象,当需要增加附加功能时,用户代码可以有选择地、按顺序的使用装饰功能包装对象。
继承关系也可以添加附加功能,但是不提倡。显然装饰模式是对继承关系的一个替代方案。综上,装饰者模式适用于动态的给一个对象添加一些额外的功能,就增加功能来说,装饰者模式比生成子类更灵活。
案例:以手表为例,基本功能是显示时间,附加功能是计步、联网。
首先将时间显示、计步、联网都作为一个单独的类存在,其次因为计步、联网是附加功能,所以计步、联网功能类需要包含基本功能的时间显示,最后因为这些功能都是属于手表的,所以这些类都继承于同一个抽象接口类,即手表类。
UML图如下:
实现代码:
class Watch
{
public:
virtual void function() = 0;
};
//时间
class TimeWatch : public Watch
{
public:
void function() { printf("It can tell you the time\n"); }
};
//计步
class StepCntWatch : public Watch
{
public:
StepCntWatch(Watch* w) : m_Watch(w) {}
void SetpCount() { printf("It can tell you the step count\n"); }
void function()
{
m_Watch->function();
SetpCount();
}
private:
Watch* m_Watch;
};
//联网
class NetworkWatch : public Watch
{
public:
NetworkWatch(Watch* w) : m_Watch(w) {}
void Networking() { printf("It can Networking\n"); }
void function()
{
m_Watch->function();
Networking();
}
private:
Watch* m_Watch;
};
int main(void)
{
Watch* twatch = NULL;
twatch = new TimeWatch;
//twatch->function();
Watch* netwatch = new NetworkWatch(twatch);
//netwatch->function();
Watch* scwatch = new StepCntWatch(netwatch);
scwatch->function();
delete scwatch;
delete netwatch;
delete twatch;
return 0;
}
编译运行:
上述用于装饰的联网类和计步类都继承自手表基类,在一些场合,可能增加的的功能并不是继承自手表基类,而是另一个抽象的附加功能类,但该抽象的附加功能类也继承自手表基类,UML图如下:
修改后:
class Watch
{
public:
virtual void function() = 0;
};
//时间
class TimeWatch : public Watch
{
public:
void function() { printf("It can tell you the time\n"); }
};
class SmartWatch : public Watch
{
public:
SmartWatch(Watch* w) : m_Watch(w) {}
protected:
Watch* m_Watch;
};
//计步
class StepCntWatch : public SmartWatch
{
public:
StepCntWatch(Watch* w) : SmartWatch(w) {}
void SetpCount() { printf("It can tell you the step count\n"); }
void function()
{
m_Watch->function();
SetpCount();
}
};
//联网
class NetworkWatch : public SmartWatch
{
public:
NetworkWatch(Watch* w) : SmartWatch(w) {}
void Networking() { printf("It can Networking\n"); }
void function()
{
m_Watch->function();
Networking();
}
};
编译运行: