zoukankan      html  css  js  c++  java
  • 设计模式--装饰者模式

      考虑程序要对一类 流 (网络流,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;
    }

      

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

  • 相关阅读:
    DevExpress v17.2新版亮点—ASP.NET篇(一)
    使用MyEclipse将HTML5移动项目迁移到PhoneGap(一)
    DevExpress v17.2新版亮点—WPF篇(七)
    什么是SpringBoot?
    application.yml中常用参数设置
    什么是MyBatis?
    什么是Spring?
    项目访问路径去掉默认的项目名
    StringUtils常用方法介绍
    Spring学习----自动装配@Resource、@Autowired、@Qualifier
  • 原文地址:https://www.cnblogs.com/David-Lin/p/10799643.html
Copyright © 2011-2022 走看看