设计模式之装饰模式(Decorator)
·
前言
在学习侯捷老师的有关设计模式的课程(李建忠老师主讲)中,老师对23种设计模式的有自己的划分,如下。所以老师讲解是按照这种顺序讲解。

单一职责:

Decorator设计模式
解决的问题
- 在某些情况下我们可能会“过度地使用继承来扩展对象的功能”,由于继承为类型引入的静态特质(多态就是动态),使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会
导致更多子类的膨胀。
如下所示,我们有文件流、网络流和内存流3种,都有流需要的read、seek和write操作。
//业务操作
class Stream{
public:
virtual void Read(int number) = 0;
virtual void Seek(int position) = 0;
virtual void Write(char data) = 0;
virtual ~Stream(){}
};
//主体类
class FileStream : public Stream{
public:
virtual void Read(int number){
//读文件流
cout << "FileStream read" << endl;
}
virtual void Seek(int position){
//定位文件流
cout << "FileStream seak" << endl;
}
virtual void Write(char data){
//写文件流
cout << "FileStream write" << endl;
}
};
class NetworkStream :public Stream{
public:
virtual void Read(int number){
//读网络流
cout << "NetworkStream read" << endl;
}
virtual void Seek(int position){
//定位网络流
cout << "NetworkStream seak" << endl;
}
virtual void Write(char data){
//写网络流
cout << "NetworkStream write" << endl;
}
};
class MemoryStream :public Stream{
public:
virtual void Read(int number){
//读网络流
cout << "MemoryStream read" << endl;
}
virtual void Seek(int position){
//定位网络流
cout << "MemoryStream seak" << endl;
}
virtual void Write(char data){
//写网络流
cout << "MemoryStream write" << endl;
}
};
现在我们需要扩展一下3种流操作,比如说,在read、seek和write操作时加密,或者是加入缓冲,或者是加密+缓冲。
那么我们很容易会想到用继承的方式实现,如下:
//扩展操作:加密
class CryptoFileStream :public FileStream{
public:
virtual void Read(int number){
//额外的加密操作...
cout << endl << "加密!" << endl;
FileStream::Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
cout << endl << "加密!" << endl;
FileStream::Seek(position);//定位文件流
//额外的加密操作...
}
virtual void Write(char data){
//额外的加密操作...
cout << endl << "加密!" << endl;
FileStream::Write(data);//写文件流
//额外的加密操作...
}
};
class CryptoNetworkStream : public NetworkStream{
public:
virtual void Read(int number){
//额外的加密操作...
cout << endl << "加密!" << endl;
NetworkStream::Read(number);//读网络流
}
virtual void Seek(int position){
//额外的加密操作...
cout << endl << "加密!" << endl;
NetworkStream::Seek(position);//定位网络流
//额外的加密操作...
}
virtual void Write(char data){
//额外的加密操作...
cout << endl << "加密!" << endl;
NetworkStream::Write(data);//写网络流
//额外的加密操作...
}
};
class CryptoMemoryStream : public MemoryStream{
public:
virtual void Read(int number){
//额外的加密操作...
cout << endl << "加密!" << endl;
MemoryStream::Read(number);//读内存流
}
virtual void Seek(int position){
//额外的加密操作...
cout << endl << "加密!" << endl;
MemoryStream::Seek(position);//定位内存流
//额外的加密操作...
}
virtual void Write(char data){
//额外的加密操作...
cout << endl << "加密!" << endl;
MemoryStream::Write(data);//写内存流
//额外的加密操作...
}
};
//扩展操作:加缓冲
class BufferedFileStream : public FileStream{
//...
};
class BufferedNetworkStream : public NetworkStream{
//...
};
class BufferedMemoryStream : public MemoryStream{
//...
};
//扩展操作:加密+缓冲
class CryptoBufferedFileStream : public FileStream{
public:
virtual void Read(int number){
//额外的加密操作...
//额外的缓冲操作...
cout << endl << "加密!" << endl;
cout << "缓冲!" << endl;
FileStream::Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
//额外的缓冲操作...
cout << endl << "加密!" << endl;
cout << "缓冲!" << endl;
FileStream::Seek(position);//定位文件流
//额外的加密操作...
//额外的缓冲操作...
}
virtual void Write(char data){
//额外的加密操作...
//额外的缓冲操作...
cout << endl << "加密!" << endl;
cout << "缓冲!" << endl;
FileStream::Write(data);//写文件流
//额外的加密操作...
//额外的缓冲操作...
}
};
/*网络和内存的加密+缓冲类似,略*/
示例图如下:

可以想象,通过这种继承的方式,以后再扩展其他的功能,子类会多么臃肿。
需要解决的问题:
- 使“对象
功能的扩展”能够根据需要来动态地实现 - 避免“扩展功能的增多”带来的子类膨胀问题,从而使得任何“功能扩展变化”所导致的影响将为最低
案例:流操作的扩展
在上述例子的例子中,由于对FileStream NetworkStream MemoryStream这3种流对read操作的加密的方式完全一样,所以有很多相同的代码。可以做如下修改
- 通过多态的方式调用
read。不用继承的方式,使用组合的方式:加一个父类指针数据成员Stream* stream。 - 因为我们还需要覆写
read方法,所以还是要继承Stream类。
这样,我们就可以将3个流FileStream NetworkStream MemoryStream的加密扩展写成一个, 如下:
class CryptoStream : public Stream//为了overide需要扩展的方法
{
Stream* stream;//获得需要扩展的主体类:FileStream NetworkStream MemoryStream
public:
CryptoStream(Stream* _stream) :stream(_stream){}
virtual void Read(int number){
//加密:
cout << "加密" << endl;
stream->Read(number);
}
virtual void Seek(int position){
cout << "加密" << endl;
stream->Seek(position);
}
virtual void Write(char data){
cout << "加密" << endl;
stream->Write(data);
}
};
同理,缓冲如下:
class BufferedStream : public Stream//为了overide需要扩展的方法
{
Stream* stream;//获得需要扩展的主体类:FileStream NetworkStream MemoryStream
public:
BufferedStream(Stream* _stream) :stream(_stream){}
virtual void Read(int number){
//缓冲:
cout << "缓冲" << endl;
stream->Read(number);
}
virtual void Seek(int position){
cout << "缓冲" << endl;
stream->Seek(position);
}
virtual void Write(char data){
cout << "缓冲" << endl;
stream->Write(data);
}
};
完整的示例:
#include <iostream>
using namespace std;
//业务操作
class Stream{
public:
virtual void Read(int number) = 0;
virtual void Seek(int position) = 0;
virtual void Write(char data) = 0;
virtual ~Stream(){}
};
//主体类
class FileStream : public Stream{
public:
virtual void Read(int number){
//读文件流
cout << "FileStream read" << endl;
}
virtual void Seek(int position){
//定位文件流
cout << "FileStream seak" << endl;
}
virtual void Write(char data){
//写文件流
cout << "FileStream write" << endl;
}
};
class NetworkStream :public Stream{
public:
virtual void Read(int number){
//读网络流
cout << "NetworkStream read" << endl;
}
virtual void Seek(int position){
//定位网络流
cout << "NetworkStream seak" << endl;
}
virtual void Write(char data){
//写网络流
cout << "NetworkStream write" << endl;
}
};
class MemoryStream :public Stream{
public:
virtual void Read(int number){
//读网络流
cout << "MemoryStream read" << endl;
}
virtual void Seek(int position){
//定位网络流
cout << "MemoryStream seak" << endl;
}
virtual void Write(char data){
//写网络流
cout << "MemoryStream write" << endl;
}
};
//加密扩展
class CryptoStream : public Stream//为了overide需要扩展的方法
{
Stream* stream;//获得需要扩展的主体类:FileStream NetworkStream MemoryStream
public:
CryptoStream(Stream* _stream) :stream(_stream){}
virtual void Read(int number){
//加密:
cout << "加密" << endl;
stream->Read(number);
}
virtual void Seek(int position){
cout << "加密" << endl;
stream->Seek(position);
}
virtual void Write(char data){
cout << "加密" << endl;
stream->Write(data);
}
};
//缓冲扩展
class BufferedStream : public Stream//为了overide需要扩展的方法
{
Stream* stream;//获得需要扩展的主体类:FileStream NetworkStream MemoryStream
public:
BufferedStream(Stream* _stream) :stream(_stream){}
virtual void Read(int number){
//缓冲:
cout << "缓冲" << endl;
stream->Read(number);
}
virtual void Seek(int position){
cout << "缓冲" << endl;
stream->Seek(position);
}
virtual void Write(char data){
cout << "缓冲" << endl;
stream->Write(data);
}
};
int main()
{
//文件流read
FileStream *fs1 = new FileStream;
fs1->Read(10);
//文件流read+加密
CryptoStream* crp = new CryptoStream(fs1);
crp->Read(10);
//文件流read+缓冲
BufferedStream* bs = new BufferedStream(fs1);
bs->Read(10);
//文件流read+缓冲+加密
BufferedStream* bs2 = new BufferedStream(crp);
bs2->Read(10);
system("pause");
return 0;
}
在上述例子中,其实也可以把BufferedStream CryptoStream 相同的数据成员Stream* stream提出来,如下,添加一个DecoratorStream 类
class DecoratorStream : public Stream//为了overide需要扩展的方法
{
protected:
Stream* stream;//获得需要扩展的主体类:FileStream NetworkStream MemoryStream
DecoratorStream(Stream* _stream) :stream(_stream){}
};
//加密扩展
class CryptoStream : public DecoratorStream
{
public:
CryptoStream(Stream* _stream) :DecoratorStream(_stream){}
virtual void Read(int number){
//加密:
cout << "加密" << endl;
stream->Read(number);
}
virtual void Seek(int position){
cout << "加密" << endl;
stream->Seek(position);
}
virtual void Write(char data){
cout << "加密" << endl;
stream->Write(data);
}
};
//缓冲扩展
class BufferedStream : public DecoratorStream
{
public:
BufferedStream(Stream* _stream) :DecoratorStream(_stream){}
virtual void Read(int number){
//缓冲:
cout << "缓冲" << endl;
stream->Read(number);
}
virtual void Seek(int position){
cout << "缓冲" << endl;
stream->Seek(position);
}
virtual void Write(char data){
cout << "缓冲" << endl;
stream->Write(data);
}
};
模式定义

- 这里的额外的职责就像
BufferedStream CryptoStream
结构

注:这里的ConcretreDecoratorA和ConcretreDecoratorB的addedState()和AddedBehavier()就是扩展功能的函数,比如例子中的加密或缓冲就可以写在这个成员函数里面。
要点总结
- 通过采用组合而非继承的手法, Decorator模式实现了在运行时动态扩展对象功能(比如说例子中的
stream->Read(number),在编译时,你无法确定是调用FileStream还是NetworkStream还是MemoryStream的read)的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。 - Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。(这是装饰模式的标志,就像例子中一样,即继承
Stream类,又有数据成员Stream* stream) - Decorator模式的目的并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”(比如例子中的
read操作扩展加密操作)——是为“装饰”的含义。
更多推荐
所有评论(0)