目錄
- “單一職責”模式
- 裝飾器模式 Decorator
- 引例
- 動機 Motivation
- 模式定義
- 結構 Structure
- 要點總結
“單一職責”模式
- 在軟件組件的設計中,如果責任劃分的不清晰,使用繼承得到的結果往往是隨著需求的變化,子類急劇膨脹,同時充斥著重復代碼,這時候的關鍵是劃清責任。
- 典型目錄
- 裝飾器模式 Decorator
- 橋接模式 Bridge
裝飾器模式 Decorator
引例
- 對于流操作,諸如文件流、網絡流、內存流等,分別對其進行諸如加密、緩存等單個或組合的操作,子類龐大。
// 業務操作 class Stream { public:virtual char Read(int number) = 0;virtual char Seek(int position) = 0;virtual char Write(char data) = 0;virtual ~Stream(){} };// 主體類 // 文件流 class FileStream : public Stream { public:virtual char Read(int number){// 讀文件流}virtual char Seek(int position){// 定位文件流}virtual char Write(char data){// 寫文件流} }; // 網絡流 class NetworkStream : public Stream { public:virtual char Read(int number){// 讀網絡流}virtual char Seek(int position){// 定位網絡流}virtual char Write(char data){// 寫網絡流} }; // 內存流 class MemoryStream : public Stream { public:virtual char Read(int number){// 讀內存流}virtual char Seek(int position){// 定位內存流}virtual char Write(char data){// 寫內存流} };//擴展操作,如加密、緩存、加密緩存 // 加密文件流 class CryptoFileStream : public FileStream { public:virtual char Read(int number){// 額外的加密操作FileStream::Read(number); // 讀文件流,這種為靜態特質 }virtual char Seek(int position){// 額外的加密操作FileStream::Seek(position); // 定位文件流}virtual char Write(char data){// 額外的加密操作FileStream::write(data);// 寫文件流} }; // 加密網絡流 class CryptoNetworkStream : public NetworkStream { public:virtual char Read(int number){// 額外的加密操作NetworkStream ::Read(number); // 讀網絡流 }virtual char Seek(int position){// 額外的加密操作NetworkStream ::Seek(position); // 定位網絡流}virtual char Write(char data){// 額外的加密操作NetworkStream ::write(data);// 寫網絡流} };// 緩存文件流 class BufferedFileStream : public FileStream { public:virtual char Read(int number){// 額外的緩存操作FileStream::Read(number); // 讀文件流 }virtual char Seek(int position){// 額外的緩存操作FileStream::Seek(position); // 定位文件流}virtual char Write(char data){// 額外的緩存操作FileStream::write(data);// 寫文件流} }; // 緩存網絡流 class BufferedNetworkStream : public NetworkStream { public:virtual char Read(int number){// 額外的緩存操作NetworkStream ::Read(number); // 讀網絡流 }virtual char Seek(int position){// 額外的緩存操作NetworkStream ::Seek(position); // 定位網絡流}virtual char Write(char data){// 額外的緩存操作NetworkStream ::write(data);// 寫網絡流} };// 加密緩存文件流 class CryptoBufferedFileStream : public FileStream { public:virtual char Read(int number){// 額外的加密操作// 額外的緩存操作FileStream::Read(number); // 讀文件流 }virtual char Seek(int position){// 額外的加密操作// 額外的緩存操作FileStream::Seek(position); // 定位文件流}virtual char Write(char data){// 額外的加密操作// 額外的緩存操作FileStream::write(data);// 寫文件流} }; // 加密網絡流 class CryptoBufferedNetworkStream : public NetworkStream { public:virtual char Read(int number){// 額外的加密操作// 額外的緩存操作NetworkStream ::Read(number); // 讀網絡流 }virtual char Seek(int position){// 額外的加密操作// 額外的緩存操作NetworkStream ::Seek(position); // 定位網絡流}virtual char Write(char data){// 額外的加密操作// 額外的緩存操作NetworkStream ::write(data);// 寫網絡流} };void Process() {// 編譯時裝配CryptoFileStream *cfs1 = new CryptoFileStream();BufferedFileStream* bfs1 = new BufferedFileStream();CryptoBufferedFileStream* cbfs1 = new CryptoBufferedFileStream(); }
如第二層m種變化類型,第三層n種變化類型,類的個數 :1+ m + m * n!/ 2
-
對第一版代碼進行重構
// 業務操作 class Stream { public:virtual char Read(int number) = 0;virtual char Seek(int position) = 0;virtual char Write(char data) = 0;virtual ~Stream(){} };// 主體類 // 文件流 class FileStream : public Stream { public:virtual char Read(int number){// 讀文件流}virtual char Seek(int position){// 定位文件流}virtual char Write(char data){// 寫文件流} }; // 網絡流 class NetworkStream : public Stream { public:virtual char Read(int number){// 讀網絡流}virtual char Seek(int position){// 定位網絡流}virtual char Write(char data){// 寫網絡流} }; // 內存流 class MemoryStream : public Stream { public:virtual char Read(int number){// 讀內存流}virtual char Seek(int position){// 定位內存流}virtual char Write(char data){// 寫內存流} };//擴展操作,如加密、緩存、加密緩存 // 加密文件流 class CryptoStream : public Stream {// FileStream* stream; 不必現在確定類型Stream* stream;// = new FileStream(); 未來確實,即運行時確定 public:CryptoStream(Stream* st) : stream(st){}virtual char Read(int number){// 額外的加密操作stream->Read(number); // 讀流 }virtual char Seek(int position){// 額外的加密操作stream->Seek(position); // 定位流}virtual char Write(char data){// 額外的加密操作stream->write(data);// 寫流} }; // 加密網絡流 class CryptoNetworkStream : public Stream {// NetworkStream * stream; 不必現在確定類型Stream* stream;// = new NetworkStream (); 未來確實,即運行時確定virtual char Read(int number){// 額外的加密操作stream->Read(number); // 讀網絡流 }virtual char Seek(int position){// 額外的加密操作stream->Seek(position); // 定位網絡流}virtual char Write(char data){// 額外的加密操作stream->write(data);// 寫網絡流} }; // 加密文件流/網絡流,合并為加密流CryptoStream,結構如下方緩存流// 緩存流 class BufferedStream : public Stream {Stream* stream; public:BufferedStream(Stream* st) : stream(st){}virtual char Read(int number){// 額外的加密操作stream->Read(number); // 讀流 }virtual char Seek(int position){// 額外的加密操作stream->Seek(position); // 定位流}virtual char Write(char data){// 額外的加密操作stream->write(data);// 寫流} };void Process() {// BufferedFileStream* bfs1 = new BufferedFileStream(); // 代碼1// CryptoBufferedFileStream* cbfs1 = new CryptoBufferedFileStream(); // 代碼1// 運行時裝配FileStream* fs1 = new FileSteam();CryptoStream* cfs1 = new CryptoStream(fs1);BufferedStream* bfs1 = new BufferedStream(fs1);CryptoStream* cbfs1 = new CryptoStream(bfs1);}
-
對第二部分代碼,繼續重構,將共有部分加入到裝飾類:DecoratorStream
// 業務操作 class Stream { public:virtual char Read(int number) = 0;virtual char Seek(int position) = 0;virtual char Write(char data) = 0;virtual ~Stream(){} };// 主體類 // 文件流 class FileStream : public Stream { public:virtual char Read(int number){// 讀文件流}virtual char Seek(int position){// 定位文件流}virtual char Write(char data){// 寫文件流} }; // 網絡流 class NetworkStream : public Stream { public:virtual char Read(int number){// 讀網絡流}virtual char Seek(int position){// 定位網絡流}virtual char Write(char data){// 寫網絡流} }; // 內存流 class MemoryStream : public Stream { public:virtual char Read(int number){// 讀內存流}virtual char Seek(int position){// 定位內存流}virtual char Write(char data){// 寫內存流} };//擴展操作,如加密、緩存、加密緩存 DecoratorStream : public Stream { protected:Stream* stream;DecoratorStream(Stream* st) : stream(st){} }// 加密文件流 class CryptoStream : public DecoratorStream { public:CryptoStream(Stream* st) : DecoratorStream(st){}virtual char Read(int number){// 額外的加密操作stream->Read(number); // 讀流 }virtual char Seek(int position){// 額外的加密操作stream->Seek(position); // 定位流}virtual char Write(char data){// 額外的加密操作stream->write(data);// 寫流} };// 緩存流 class BufferedStream : public DecoratorStream { public:BufferedStream(Stream* st) : stream(st){}virtual char Read(int number){// 額外的加密操作stream->Read(number); // 讀流 }virtual char Seek(int position){// 額外的加密操作stream->Seek(position); // 定位流}virtual char Write(char data){// 額外的加密操作stream->write(data);// 寫流} };void Process() {// 運行時裝配FileStream* fs1 = new FileSteam();CryptoStream* cfs1 = new CryptoStream(fs1);BufferedStream* bfs1 = new BufferedStream(fs1);CryptoStream* cbfs1 = new CryptoStream(bfs1);}
類的個數: 1 + m + 1 + n,使用組合(裝飾器類中含有被修飾類的指針),來減少類的數量。
動機 Motivation
- 在某些情況下,我們可能會“過度地使用繼承來擴展對象的功能”,由于繼承為類型引入的靜態特質,使得這種擴展方式缺乏靈活性;并且隨著子類的增多(擴展功能的增多),各種子類的組合(擴展功能的組合)會導致更多子類的膨脹。
模式定義
動態(組合)地給一個對象增加一些額外的職責。就增加功能而言,Decorator模式比生成子類(繼承)更為靈活(消除重復代碼及減少子類個數)。
結構 Structure
紅色為穩定部分,藍色為變化部分。
要點總結
- 通過采用組合而非繼承的手法,裝飾器模式實現了在運行時動態擴展對象功能的能力,而且可以根據需要擴展多個功能,避免了使用繼承帶來的“靈活性差”和“多子類衍生”問題。
- Decorator 裝飾器類在接口上表現為 is-a Component 的繼承關系,即Decorator裝飾器類繼承了Component 所具有的接口;但在實現上又表現為 has-a Component的組合關系,即Decorator裝飾器類又使用了另外一個Component類。
- 裝飾器模式的目的并非解決“多子類衍生的多繼承”問題,其應用的要點在于解決“主體類在多個方向上的擴展功能”——是為“裝飾”的含義。
來源:極客班——C++設計模式入門