博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式--装饰者模式
阅读量:6256 次
发布时间:2019-06-22

本文共 3623 字,大约阅读时间需要 12 分钟。

  考虑程序要对一类 流 (网络流,IO流等等)进行操作。进行什么操作呢?可能在读(Read)这个流的时候对这个流进行加密,也可能对这个流进行缓存。

  那么很自然的能设计出以下这些类

class Stream {public:  void Read();};class IOStream : public Stream {};                   // 输入输出流class NetStream: public Stream {};                    // 网络流class BufferedIOStream : public IOStream {public:  void Read() {                       // 实现了缓存功能的读操作    Buffer();    IOStream::Read();  }  void Buffer() {}              };       class EncryptIOStream : public IOStream {public:  void Read() {                      // 实现了加密功能的读操作    Encrypt();    IOStream::Read();  }  void Encrypt();                     }// 实现加密和缓存功能的输入输出流class BufferedEncryptIOStream : public EncryptIOStream,                    public BufferedIOStream {public:   void Read() {    EncryptIOStream::Encrypt();    BufferedIOStream::Read();  }};// 网络流同理class BufferedNetStream : public NetStream ......

 

  那么这样做的缺点有什么呢?试想一下,如果我现在要对流增加新的操作,比如说要将流输出。你可能会有如下设计

class PrintIOStream : public IOStream {public:   void Read() {    Print();    IOStream::Read();  }  void Print();}class BufferedPrintIOStream : public BufferedIOStream,                  public PrintIOStream {  // 既可以加密有可以缓存的流public:   void Read() {    PrintIOStream::Print();    BufferedIOStream::Read();  }};  class EncryptPrintIOStream : public EncryptIOStream,                  public PrintIOStream {};  // 既可以加密有可以打印的IO流class BufferedEncryptPrintIOStream : public BufferedPrintIOStream,                      public EncryptPrintIOStream {};

 

  哇靠,有没有搞错!只不过是要求增加了一个新的打印的功能,结果多出了这么多的类。如果继续增加新功能的话,类的数量之多可想而知。这种现象被称作类爆炸

当然了,你也可以说只设计一个BufferedEncryptPrintIOStream。但是假如你某个时刻不需要打印功能的话,那么打印功能就是累赘,这显然违背了接口隔离原则

 

  这时候就需要一种更好的设计方法----装饰者模式

  试想一下,如果我们通过组合的方式来设计类会不会有上述问题呢?答案是不会。

// 装饰者模式一瞥class BufferedStream : public Stream {public:  BufferedStream(Stream* stm) : stream(stm) {}  void Read() {
    Buffer();     myStream->Read();   }   void Buffer();private:  Stream* myStream;};

  嗯?这个类怎么这么奇怪,又是继承了Stream,里面又包含了一个Stream。这其实就是装饰者模式的精髓。之所以继承是因为BufferedStream首先是个流,它可能有一些Stream通用的性质。而为什么它的成员函数也包含个Stream对象?请注意,这里的Stream是一个指针,对c++敏感的朋友可能已经意识到了指针意味着可以动态绑定。那么我们看看如何使用这个BufferedStream以实现上述的各种功能

// 如果我们想要一个缓冲的IO流IOStream* stm = new IOStream();BufferedStream* bufferedStm = new BufferedStream(stm);   bufferedStm->Read();// 如果我们要一个缓冲的加密的IO流EncryptStream* encryptStream = new EncryptStram(new IOStream);BufferedStream* bufEncStream = new BufferedStream(encryptStream);bufEncStream->Read();

  是不是觉得很神奇?关键点在于对流的层层包装,比如说先把流包装成可打印的流,那么它就能实现打印的功能了。在这个基础上把它包装成缓存流,那么它既有缓存功能有有打印功能。如果需要更多的功能怎么办?继续包装就是了。这样子就无需为新的功能拓展类,从而避免了类爆炸的问题

  

  以上就是装饰者模式,接下来给出装饰者模式的完整设计代码

class Stream {public:  void Read();};class IOStream : public Stream {};class PrintStream : Stream {public:  PrintStream(Stream* stm) : myStream(stm) {}  void Read() {    Print();    myStream->Read();  }  void Print() {}private:  Stream* myStream;};class BufferedStream : Stream {public:  BufferedStream(Stream* stm) : myStream(stm) {}  void Read() {    Buffer();    myStream->Read();  }    void Buffer();private:  Stream* myStream;};class EncryptStream : Stream {public:  EncryptStream(Stream* stm) : myStream(stm) {}  void Read() {    Encrypt();    myStream->Read();  }  void Encrypt();private:  Stream* myStream;}// 只需这几个类就能完成所有需要的功能,接下来看看使用方法IOStream* iostm = new IOStream();BufferedStream* bufferedPrintEncryptStream =   new BufferedStream(new PrintStream(new EncryptStream(iostm)));

  

  更近一步。细心的朋友可能已经发现了三个类中都有一个myStream成员,那么能优化的是将myStream放在一个新的类中,然后让这三个类继承这个新的类

class MyStream : Stream {
public:   MyStream(Stream* stm) : myStream(stm) {} private:   Stream* myStream; }

  

  以上就是装饰者模式的所有内容

 

转载于:https://www.cnblogs.com/David-Lin/p/10799643.html

你可能感兴趣的文章
基础知识系列☞闲言
查看>>
蓝牙Ibeacon室内定位和微信摇一摇周边原理分析
查看>>
架构设计:负载均衡层设计方案(7)——LVS + Keepalived + Nginx安装及配置
查看>>
virtualbox端口转发
查看>>
DiscuzX2.5 程序底层架构
查看>>
Jenkins_多项目构建(二):使用Maven聚集关系
查看>>
三大做空工具详解
查看>>
linux全方位掌握一个命令--思路比方法更重要
查看>>
[Flexbox] Use Flex to Scale Background Image
查看>>
【等待事件】序列等待事件总结(enq: SQ - contention、row cache lock、DFS lock handle和enq: SV - contention)...
查看>>
算法与数据结构(七) AOV网的拓扑排序(Swift版)
查看>>
maven pom.xml解释 (转)
查看>>
markdown to html
查看>>
Pspice仿真器
查看>>
ogg 、 Shareplex和DSG RealSync 对比
查看>>
NK3C程序配置
查看>>
webrtc中APM(AudioProcessing module)的使用2
查看>>
lunix的查看Tomcat目录下日志的快速操作
查看>>
zabbix添加邮件报警机制
查看>>
微信开放之模板消息
查看>>