zoukankan      html  css  js  c++  java
  • 设计模式学习总结:(5)装饰模式

    装饰模式:

    顾名思义,就是装饰,比如手机套,用来装饰手机,但是,作为手机套的实现是不影响手机的,手机套就像一个装饰器。在比方,相框,相框花边,他们都是为了给相片添加新的额外的功能,但是这种功能本身不影响相片的性质。

    行为模式

    意图:

    动态给一个对象添加额外的职责。就增加功能而言,装饰模式相比生成子类更为灵活。

    比生成子类更灵活,确实,相比用继承方式去添加职责,装饰器模式表现非常灵活。

     比如这样的例子,流操作,一开始有文件流和网络流,如果用继承的方式,我想得这样写:

    class Stream{
    publicvirtual handleStream()=0;
        virtual ~Stream(){}
         
    };

    文件流:

    #include<iostream>
    using namespace std; class FileStream: public Stream{ public: FileStream(){} virtual ~FileStream(){} void handleStream(){ cout<<"处理文件流"<<endl; } };

    网络流:

    #include<iostream>
    using namespace std;
    class NetwordStream: public Stream{
    public:
        NetwordStream(){}
        virtual ~NetwordStream
        void handleStream(){  cout<<"网络流"<<endl; }
    };

    如果要加密两种流,用继承我们还得这么写:

    class CryptoFileStream :public FileStream{
    public:
        CryptoFileStream():FileStream(){}
        virtual ~CryptoFileStream();
        void handleStream()
        { 
            FileStream::handleStream(); 
            cout<<"加密"<<endl;
        }
    };
    class CryptoFileStream :public NetwordStream{
    public:
        CryptoFileStream():NetwordStream(){}
        virtual ~CryptoFileStream();
        void handleStream()
        { 
            NetwordStream::handleStream(); 
            cout<<"加密"<<endl;
        }
    };

    假如还有个转码的装饰类,那我们还得再写两个这样的类,我这里就不写了,不仅代码冗余,而且类膨胀严重。如果有n种具体子类和m中搭配装饰,粗略算一下应该要1+n+n*m+n*(2^m-m-1)个类,基类一个,然后有多少种子类可能就是n,而对类进行单一装饰是n*m种类,m种装饰器的搭配方式应该是2^m-m-1(二项式公式减前两项),n种子类就有n*(2^m-m-1).

    当然,这不是重点,重点是我们用装饰模式可以如何实现,先看看书上给的结构图:

    我们看到四个基本的角色:

    1.抽象接口对象(component)

        最基本的机构对象,用于动态添加职责

    2.具体的实际对象,具有具体职责的对象(concrete component)

    3.总装饰器(decorator)

      需要保存一个component对象用于多态,同时继承component用于添加额外职责。

    4.具体装饰

      实现你需要实现的额外职责。

    最基本的基类:

    class AbStream
    {
    public:
        virtual void handleBuff()=0;
        virtual ~AbStream(){}
    };

    文件流类:

    class FileStream:public AbStream
    {
    public:
        FileStream(){}
        virtual ~FileStream(){}
        void handleBuff();
    };
    
    void FileStream::handleBuff()
    {
        cout << "处理文件流" << endl;
    }

    网络流:

    class NetwordStream:public AbStream
    {
    public:
        NetwordStream();
        virtual ~NetwordStream();
        void handleBuff();
    };
    void NetwordStream::handleBuff()
    {
        cout << "处理网络流" << endl;
    }

    接下来是装饰器:

    class StreamDocorator:public AbStream
    {
    public:
    
        virtual ~StreamDocorator();
        void handleBuff();
    protected:
        StreamDocorator(AbStream *stream) :_stream(stream)
        {
    
        }
    private:
        AbStream *_stream;
    };
    
    void StreamDocorator::handleBuff()
    {
        _stream->handleBuff();
    }

      StreamDocorator::~StreamDocorator()
      {

    
    

      }

     

    然后是加密,作为具体装饰类:

    class CryptoStream :public StreamDocorator
    {
    public:
        CryptoStream(AbStream *stream) : StreamDocorator(stream){}
        virtual ~CryptoStream(){}
        void handleBuff()
        {
            StreamDocorator::handleBuff();
            cout << "对数据流加密" << endl;
        }
    };

    如果还有转码:

    class BuffStream :public StreamDocorator
    {
    public:
        BuffStream(AbStream *stream) :StreamDocorator(stream){}
        virtual ~BuffStream(){}
        void handleBuff()
        {
            StreamDocorator::handleBuff();
            cout << "二进制转码" << endl;
        }
    };

    然后我们就可以测试一下:

    int main()
    {
        FileStream *a = new FileStream();
        CryptoStream *cS = new CryptoStream(a);
        cS->handleBuff();
    cout << "----------------------" << endl; BuffStream
    *bcS = new BuffStream(cS); //还可以进行复合装饰 bcS->handleBuff(); return 0; }

    运行后的结果:

    对比装饰模式和策略模式:

    最根本的是装饰模式对于服务的对象是透明的,这个服务的对象就好比上面例子中的FileStream,透明应该这么理解,对于FileStream,它完全不知道有装饰器这样的兄弟,装饰器存不存在对于FileStream并没有什么影响,而策略模式中,比如上次例子中的Economic类,实际上用策略模式也能实现FileStream这个逻辑,但是对于FileStream,它需要保持关于装饰器(策略类,这里假设是策略模式实现)的引用,那么这是不透明。

    而且如果抽象Stream如果过于复杂,用策略模式也是比较好的选择,当然,装饰器更加强调了多种可能(指装饰和策略)的搭配,而策略好像并无法达成这个要求。

    当然,最后的还是要感慨下,也许在以后的开发过程中能够领悟更多,毕竟古人常说:"纸上得来终觉浅,绝知此事要躬行".

  • 相关阅读:
    Python Redis 五大数据类型
    Python 魔法方法
    Python 静态方法,类方法,属性方法
    Python 反射
    Python 中 封装,继承,多态
    Redis 事务
    Redis 哨兵集群
    装饰器,迭代器,生成器
    Flume与kafka集成
    hbase 可视化工具 HBaseXplorer---HbaseGUI
  • 原文地址:https://www.cnblogs.com/wuweixin/p/5425932.html
Copyright © 2011-2022 走看看