目录
- “单一职责”模式
- 装饰器模式 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++设计模式入门