“單一職責”模式:
在軟體元件的設計中,如果責任劃分的不清晰,使用繼承得到的結構往往是随着需求的變化,子類急劇膨脹,同時充斥着重複代碼,這時候的關鍵是劃清責任。
典型模式
- Decorator
- Bridge
這兩個模式在責任的變現上十分突出。
類的數量:1+n+n*m!/2
當一個變量的聲明類型都是 某個類型的子類的時候,應該把它聲明為某個類型
編譯時讓他們一樣,運作時讓他們不一樣===》絕大多數設計模式的真谛
編譯時讓它共同複用它的變化,多态支援。
Stream* stream = new FileStream(); new NetworkStream(); new MemoryStream();
樣子
//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類在接口上表現為 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大師就是大師。妞