设计模式之装饰模式(Decorator)

目录

  • 前言
  • Decorator设计模式
    • 解决的问题
    • 案例:流操作的扩展
    • 模式定义
    • 结构
    • 要点总结

前言

在学习侯捷老师的有关设计模式的课程(李建忠老师主讲)中,老师对23种设计模式的有自己的划分,如下。所以老师讲解是按照这种顺序讲解。
设计模式之装饰模式(Decorator)_第1张图片
单一职责:
在这里插入图片描述

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);//写文件流
		//额外的加密操作...
		//额外的缓冲操作...
	}
};
/*网络和内存的加密+缓冲类似,略*/

示例图如下:
设计模式之装饰模式(Decorator)_第2张图片

可以想象,通过这种继承的方式,以后再扩展其他的功能,子类会多么臃肿。

需要解决的问题:

  1. 使“对象功能的扩展”能够根据需要来动态地实现
  2. 避免“扩展功能的增多”带来的子类膨胀问题,从而使得任何“功能扩展变化”所导致的影响将为最低

案例:流操作的扩展

在上述例子的例子中,由于对FileStream NetworkStream MemoryStream这3种流对read操作的加密的方式完全一样,所以有很多相同的代码。可以做如下修改

  1. 通过多态的方式调用read。不用继承的方式,使用组合的方式:加一个父类指针数据成员Stream* stream
  2. 因为我们还需要覆写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 
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);
	}
};

模式定义

设计模式之装饰模式(Decorator)_第3张图片

  • 这里的额外的职责就像BufferedStream CryptoStream

结构

设计模式之装饰模式(Decorator)_第4张图片
注:这里的ConcretreDecoratorAConcretreDecoratorBaddedState()AddedBehavier()就是扩展功能的函数,比如例子中的加密缓冲就可以写在这个成员函数里面。

要点总结

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

你可能感兴趣的:(设计模式,设计模式,c++,visual,studio,decorator,pattern)