天天看點

設計模式----裝飾模式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大師就是大師。妞

繼續閱讀