设计模式学习总结:(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如果过于复杂,用策略模式也是比较好的选择,当然,装饰器更加强调了多种可能(指装饰和策略)的搭配,而策略好像并无法达成这个要求。

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

原文地址:https://www.cnblogs.com/wuweixin/p/5425932.html