天天看点

设计模式----装饰模式Decorator

作者:初春de小草
设计模式----装饰模式Decorator

“单一职责”模式:

在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结构往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任。

典型模式

  • Decorator
  • Bridge

这两个模式在责任的变现上十分突出。

类的数量:1+n+n*m!/2

设计模式----装饰模式Decorator

当一个变量的声明类型都是 某个类型的子类的时候,应该把它声明为某个类型

编译时让他们一样,运行时让他们不一样===》绝大多数设计模式的真谛

编译时让它共同复用它的变化,多态支持。

Stream* stream = new FileStream(); new NetworkStream(); new MemoryStream();

样子

设计模式----装饰模式Decorator
//decorator1.cpp
//io流操作

//业务操作 基类
class Stream
{
public:
	virtual char Read(int number) = 0;
	virtual void Seek(int position) = 0;
	virtual void Write(char data) = 0;

	virtual ~Stream() {}

};

//主体类 文件流
class FileStream : public Stream
{
public:
	virtual char Read(int number)
	{
		//读文件流
	}
	virtual void Seek(int position)
	{
		//定位文件流
	}
	virtual void Write(char data)
	{
		//写文件流
	}
};

//网络流
class NetworkStream :public Stream
{
public:
	virtual char Read(int number)
	{
		//读网络流
	}
	virtual void Seek(int position)
	{
		//定位网络流
	}
	virtual void Write(char data)
	{
		//写网络流
	}
};

//内存流
class MemoryStream :public Stream
{
public:
	virtual char Read(int number)
	{
		//读内存流
	}
	virtual void Seek(int position)
	{
		//定位内存流
	}
	virtual void Write(char data)
	{
		//写内存流
	}
};
//------------------------------------------
//扩展操作--对文件流加密
class CryptoFileStream :public FileStream
{
public:
	virtual char Read(int number)
	{
		//额外的加密操作...
		FileStream::Read(number);//读文件流
	}
	virtual void Seek(int position)
	{
		//额外的加密操作...
		FileStream::Seek(position);//读文件流
		//额外的加密操作...
	}
	virtual void Write(char data)
	{
		//额外的加密操作...
		FileStream::Write(data);//读文件流
		//额外的加密操作...
	}
};

//对网络流加密
class CryptoNetworkStream :public NetworkStream
{
public:
	virtual char Read(int number)
	{
		//额外的加密操作...
		NetworkStream::Read(number);//读文件流
	}
	virtual void Seek(int position)
	{
		//额外的加密操作...
		NetworkStream::Seek(position);//读文件流
		//额外的加密操作...
	}
	virtual void Write(char data)
	{
		//额外的加密操作...
		NetworkStream::Write(data);//读文件流
		//额外的加密操作...
	}
};

//对内存流加密
class CryptoMemoryStream :public MemoryStream
{
public:
	virtual char Read(int number)
	{
		//额外的加密操作...
		MemoryStream::Read(number);//读文件流
	}
	virtual void Seek(int position)
	{
		//额外的加密操作...
		MemoryStream::Seek(position);//读文件流
		//额外的加密操作...
	}
	virtual void Write(char data)
	{
		//额外的加密操作...
		MemoryStream::Write(data);//读文件流
		//额外的加密操作...
	}
};
//-----------------------------------------------------------

//缓冲
class BufferedFileStream :public FileStream
{
	//...
};

class BufferedNetworkStream :public NetworkStream
{
	//...
};

class BufferedMemoryStream :public MemoryStream
{
	//..
};

//对缓冲加密
class CryBufferedFileStream :public FileStream
{
public:
	virtual char Read(int number)
	{
		//额外的加密操作...
		//额外的缓冲操作...
		FileStream::Read(number);//读文件流
	}

	virtual void Seek(int position)
	{
		//额外的加密操作...
		//额外的缓冲操作...
		FileStream::Seek(position);//定位文件流
		//额外的加密操作...
		//额外的缓冲操作...

	}
};           
//decorator2.cpp  GeekBand
//io流操作 本文件对上一个文件进行修改

//业务操作 基类
class Stream
{

public:
	virtual char Read(int number) = 0;
	virtual void Seek(int position) = 0;
	virtual void Write(char data) = 0;

	virtual ~Stream() {}

};

//主体类 文件流
class FileStream : public Stream
{
public:
	virtual char Read(int number)
	{
		//读文件流
	}
	virtual void Seek(int position)
	{
		//定位文件流
	}
	virtual void Write(char data)
	{
		//写文件流
	}
};

//网络流
class NetworkStream :public Stream
{
public:
	virtual char Read(int number)
	{
		//读网络流
	}
	virtual void Seek(int position)
	{
		//定位网络流
	}
	virtual void Write(char data)
	{
		//写网络流
	}
};

//内存流
class MemoryStream :public Stream
{
public:
	virtual char Read(int number)
	{
		//读内存流
	}
	virtual void Seek(int position)
	{
		//定位内存流
	}
	virtual void Write(char data)
	{
		//写内存流
	}
};

//先把继承用组合替换。组合优于继承
//当一个变量的声明类型都是 某个类型的子类的时候,应该把它声明为某个类型
//------------------------------------------
//扩展操作--对文件流加密
class CryptoFileStream :public Stream//还是要加上基类,为保证虚函数的接口规范
{
	//先把继承用组合替换。组合优于继承
	//当一个变量的声明类型都是 某个类型的子类的时候,应该把它声明为某个类型
	Stream* stream;//=new FileStream();
public:
	virtual char Read(int number)
	{
		//额外的加密操作...
		stream->Read(number);//读文件流
	}
	virtual void Seek(int position)
	{
		//额外的加密操作...
		stream->Seek(position);//读文件流
		//额外的加密操作...
	}
	virtual void Write(char data)
	{
		//额外的加密操作...
		stream->Write(data);//读文件流
		//额外的加密操作...
	}
};

//对网络流加密
class CryptoNetworkStream :public Stream//还是要加上基类,为保证虚函数的接口规范
{
	Stream* stream; //=new NetworkStream();
public:
	virtual char Read(int number)
	{
		//额外的加密操作...
		stream->Read(number);//读文件流
	}
	virtual void Seek(int position)
	{
		//额外的加密操作...
		stream->Seek(position);//读文件流
		//额外的加密操作...
	}
	virtual void Write(char data)
	{
		//额外的加密操作...
		stream->:Write(data);//读文件流
		//额外的加密操作...
	}
};

//对内存流加密
class CryptoMemoryStream :public Stream//还是要加上基类,为保证虚函数的接口规范
{
	Stream* stream;// = new MemoryStream();
public:
	virtual char Read(int number)
	{
		//额外的加密操作...
		stream->Read(number);//读文件流
	}
	virtual void Seek(int position)
	{
		//额外的加密操作...
		stream->Seek(position);//读文件流
		//额外的加密操作...
	}
	virtual void Write(char data)
	{
		//额外的加密操作...
		stream->Write(data);//读文件流
		//额外的加密操作...
	}
};

/*
*这样做了以后发现这三个类只有类名不一样,其余都一样===》合并,用一个类就可以了
* 这个地方既有Stream基类,也有Stream成员变量
*/
class CryptoStream :public Stream//还是要加上基类,为保证虚函数的接口规范
{
	//先把继承用组合替换。组合优于继承
	//当一个变量的声明类型都是 某个类型的子类的时候,应该把它声明为某个类型
	Stream* stream;//。。。
public:
	CryptoStream(Stream* stm) :
		stream(stm)
	{

	}
	virtual char Read(int number)
	{
		//额外的加密操作...
		stream->Read(number);//读文件流
	}
	virtual void Seek(int position)
	{
		//额外的加密操作...
		stream->Seek(position);//读文件流
		//额外的加密操作...
	}
	virtual void Write(char data)
	{
		//额外的加密操作...
		stream->Write(data);//读文件流
		//额外的加密操作...
	}
};
//-----------------------------------------------------------

//~~~~~~~~~~~~~~~~~
//缓冲
class BufferedFileStream :public FileStream
{
	//...
};

class BufferedNetworkStream :public NetworkStream
{
	//...
};

class BufferedMemoryStream :public MemoryStream
{
	//..
};
//同样,buffer也可以这样
//缓冲
class BufferedStream :public Stream
{
	Stream* stream;
	//...
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//对缓冲加密
class CrytoBufferedFileStream :public FileStream
{
public:
	virtual char Read(int number)
	{
		//额外的加密操作...
		//额外的缓冲操作...
		FileStream::Read(number);//读文件流
	}

	virtual void Seek(int position)
	{
		//额外的加密操作...
		//额外的缓冲操作...
		FileStream::Seek(position);//定位文件流
		//额外的加密操作...
		//额外的缓冲操作...

	}
};

void Process()
{
	//编译时装配
	CryptoFileStream* fs1 = new CryptoFileStream();
	BufferedFileStream* fs2 = new BufferedFileStream();
	CrytoBufferedFileStream* fs3 = new CrytoBufferedFileStream();

}

void Process_2()
{
	//运行时装配 ====替换上面
	FileStream* s1 = new FileStream();
	CryptoStream* s2 = new CryptoStream(s1);

	BufferedStream* s3 = new BufferedStream(s1);
	BufferedStream* s4 = new BufferedStream(s2);

}           
//decorator3.cpp  GeekBand
//io流操作 本文件对上一个文件进行修改

//业务操作 基类
class Stream
{

public:
	virtual char Read(int number) = 0;
	virtual void Seek(int position) = 0;
	virtual void Write(char data) = 0;

	virtual ~Stream() {}

};

//主体类 文件流
class FileStream : public Stream
{
public:
	virtual char Read(int number)
	{
		//读文件流
	}
	virtual void Seek(int position)
	{
		//定位文件流
	}
	virtual void Write(char data)
	{
		//写文件流
	}
};

//网络流
class NetworkStream :public Stream
{
public:
	virtual char Read(int number)
	{
		//读网络流
	}
	virtual void Seek(int position)
	{
		//定位网络流
	}
	virtual void Write(char data)
	{
		//写网络流
	}
};

//内存流
class MemoryStream :public Stream
{
public:
	virtual char Read(int number)
	{
		//读内存流
	}
	virtual void Seek(int position)
	{
		//定位内存流
	}
	virtual void Write(char data)
	{
		//写内存流
	}
};

//装饰类就是把这个Stream往上提
//扩展操作,就是在谁的基础上操作就是装饰。附着在其他地方。
class DecoratorStream :public Stream
{
protected://从子类提取上来的,给子类用的,所以是protected
	Stream* stream;//。。。这个是设计的核心,用组合的方式引出一种多态的支持未来的变化
	DecoratorStream(Stream* stm)
		:stream(stm)
	{
	}

};

class CryptoStream :public DecoratorStream
{
public:
	CryptoStream(Stream* stm) :
		DecoratorStream(stm)
	{

	}
	virtual char Read(int number)
	{
		//额外的加密操作...
		stream->Read(number);//读文件流
	}
	virtual void Seek(int position)
	{
		//额外的加密操作...
		stream->Seek(position);//读文件流
		//额外的加密操作...
	}
	virtual void Write(char data)
	{
		//额外的加密操作...
		stream->Write(data);//读文件流
		//额外的加密操作...
	}
};
//-----------------------------------------------------------

//~~~~~~~~~~~~~~~~~
//缓冲
//同样,buffer也可以这样
//缓冲
class BufferedStream :public DecoratorStream
{
public:
	BufferedStream(Stream* stm)
		:DecoratorStream(stm)
	{
	}
	//...
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//对缓冲加密
class CrytoBufferedFileStream :public FileStream
{
public:
	virtual char Read(int number)
	{
		//额外的加密操作...
		//额外的缓冲操作...
		FileStream::Read(number);//读文件流
	}

	virtual void Seek(int position)
	{
		//额外的加密操作...
		//额外的缓冲操作...
		FileStream::Seek(position);//定位文件流
		//额外的加密操作...
		//额外的缓冲操作...

	}
};

void Process()
{
	//编译时装配
	CryptoFileStream* fs1 = new CryptoFileStream();
	BufferedFileStream* fs2 = new BufferedFileStream();
	CrytoBufferedFileStream* fs3 = new CrytoBufferedFileStream();

}

void Process_2()
{
	//运行时装配 ====替换上面
	FileStream* s1 = new FileStream();
	CryptoStream* s2 = new CryptoStream(s1);

	BufferedStream* s3 = new BufferedStream(s1);
	BufferedStream* s4 = new BufferedStream(s2);

}           

n+m个类

类的数量:1+n+1+m

对继承的不良使用。

组合更好使用

//扩展操作,就是在谁的基础上操作就是装饰。附着在其他地方。
class DecoratorStream :public Stream
{
protected://从子类提取上来的,给子类用的,所以是protected
	Stream* stream;//。。。这个是设计的核心,用组合的方式引出一种多态的支持未来的变化
	DecoratorStream(Stream* stm)
		:stream(stm)
	{
	}

};           

动机(Motivation)

在某些清空下,我们可能会“过度地使用继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。

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

静态特质:

FileStream::Read(number);//读文件流

NetworkStream::Read(number);//读文件流

MemoryStream::Read(number);//读文件流

//多态指针调用

//动态特质 组合实现的

stream->Read(number);//读文件流

模式定义

动态(组合)地给一个对象增加一些额外地职责。就增加功能而言,Decorator模式比子类(继承)更为灵活(消除复用代码&减少子类个数)。

----《设计模式》 GoF

设计模式----装饰模式Decorator

要点总结

  • 通过采用组合而非继承地手法,Decorator模式实现了在运行时动态扩展对象功能地能力,而且可以根据需要扩展多个功能。避免了使用继承带来地“灵活性差”和“多子类衍生问题”。
  • Decorator类在接口上表现为 is-a Component 的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。
  • Decorator模式的目的并非解决“多子类衍生的多继承”问题。Decorator模式应用的要点在于解决“主体类”在多个方向上的扩展功能----是为“装饰”的含义。

既继承、又组合 表现为has-a.。

Decorator特点:

一个类中 父类是Stream, 类成员中含有Stream 对象。就要高度怀疑(99%)是Decorator模式

因为正常情况下不会这么干,要么继承要么组合,这么做肯定又独特的设计。

父类与构造器参数是同一类型===》Decorator模式

class  DecoratorStream:public Stream
{
	protected:
 		 Stream  *stream;
  	DecoratorStream(Stream* stm):stream(stm)
  {}
};           

主题操作,扩展操作。

捶胸顿足的感觉啊。。GoF大师就是大师。妞

继续阅读