[设计模式]装饰模式

[设计模式]装饰模式

1. “单一职责原则”

  设计模式中八大设计原则中有一个“单一职责原则”,一个类一般只有一个职责,如果职责过多,随着类的派生,其会越来越混乱。

  我们现在通过Stream派生出FileStream,MemoryStram;同时对流又存在加密,缓冲,既加密又缓冲等等,未来还会存在更多操作。

  如果没学过设计模式,则写出下面代码一点都不奇怪,其随着需求的增多代码量急剧增加!其原因就是违背了“单一职责原则”,多继承的类混杂在一起。

//业务操作
class Stream{
publicvirtual char Read(int number)=0;
    virtual void Seek(int position)=0;
    virtual void Write(char data)=0;
    
    virtual ~Stream(){}
};

//主体类
class FileStream: public Stream{
public:
    virtual char Read(int number){
        //读文件流
    }
    virtual void Seek(int position){
        //定位文件流
    }
    virtual void Write(char data){
        //写文件流
    }

};

class NetworkStream :public Stream{
public:
    virtual char Read(int number){
        //读网络流
    }
    virtual void Seek(int position){
        //定位网络流
    }
    virtual void Write(char data){
        //写网络流
    }
    
};

class MemoryStream :public Stream{
public:
    virtual char Read(int number){
        //读内存流
    }
    virtual void Seek(int position){
        //定位内存流
    }
    virtual void Write(char data){
        //写内存流
    }
    
};

//扩展操作
class CryptoFileStream :public FileStream{
public:
    virtual char Read(int number){
       
        //额外的加密操作...
        FileStream::Read(number);//读文件流
        
    }
    virtual void Seek(int position){
        //额外的加密操作...
        FileStream::Seek(position);//定位文件流
        //额外的加密操作...
    }
    virtual void Write(byte data){
        //额外的加密操作...
        FileStream::Write(data);//写文件流
        //额外的加密操作...
    }
};

class CryptoNetworkStream : :public NetworkStream{
public:
    virtual char Read(int number){
        
        //额外的加密操作...
        NetworkStream::Read(number);//读网络流
    }
    virtual void Seek(int position){
        //额外的加密操作...
        NetworkStream::Seek(position);//定位网络流
        //额外的加密操作...
    }
    virtual void Write(byte data){
        //额外的加密操作...
        NetworkStream::Write(data);//写网络流
        //额外的加密操作...
    }
};

class CryptoMemoryStream : public MemoryStream{
public:
    virtual char Read(int number){
        
        //额外的加密操作...
        MemoryStream::Read(number);//读内存流
    }
    virtual void Seek(int position){
        //额外的加密操作...
        MemoryStream::Seek(position);//定位内存流
        //额外的加密操作...
    }
    virtual void Write(byte data){
        //额外的加密操作...
        MemoryStream::Write(data);//写内存流
        //额外的加密操作...
    }
};

class BufferedFileStream : public FileStream{
    //...
};

class BufferedNetworkStream : public NetworkStream{
    //...
};

class BufferedMemoryStream : public MemoryStream{
    //...
}




class CryptoBufferedFileStream :public FileStream{
public:
    virtual char Read(int number){
        
        //额外的加密操作...
        //额外的缓冲操作...
        FileStream::Read(number);//读文件流
    }
    virtual void Seek(int position){
        //额外的加密操作...
        //额外的缓冲操作...
        FileStream::Seek(position);//定位文件流
        //额外的加密操作...
        //额外的缓冲操作...
    }
    virtual void Write(byte data){
        //额外的加密操作...
        //额外的缓冲操作...
        FileStream::Write(data);//写文件流
        //额外的加密操作...
        //额外的缓冲操作...
    }
};



void Process(){

        //编译时装配
    CryptoFileStream *fs1 = new CryptoFileStream();

    BufferedFileStream *fs2 = new BufferedFileStream();

    CryptoBufferedFileStream *fs3 =new CryptoBufferedFileStream();

}
View Code

2. 装饰模式

  设计模式中存在一句话,“继承优于组合”。面向对象设计语言仅C++支持多继承,多继承会带来代码冗杂的问题。

  我们现在就采用组合的方式来解决多继承带来的困扰,对于Stream,一个核心的路线就是Stream的读写操作,而缓冲加密等起到装饰作用。

  我们将起到装饰作用的用一个类将其打包,如果一个类需要用到装饰类,之后通过装饰类派生来获得这个装饰属性,当然装饰类同样继承于基类。

  因为其同样继承于基类,所以类的主体属性并没有改变,依然是Stream流,这样也避免了多继承,而是采用组合继承的方式,需要什么功能通过继承添加什么功能。

3. 装饰模式核心代码

  装饰模式核心代码如下,其最为显著的特点:即派生于基类,有存在一个其基类指针成员。

  ① 派生于基类的原因是规范接口,当类的实例x通过装饰类a获取功能a,其同样可以通过装饰类b获取功能b.....。

  ② 存在基类指针成员的原因是获取实例x的功能,该指针成员代指x,x->Read()与x->Write(),这样就不用再用代码去写这些功能。

  可以说,如果同时存在上面两种特性,这段代码99%的概率使用装饰模式。

// 装饰器
class DecorationStream : public Stream {
public:
    Stream* stream;
    // 构造函数为流赋值
    DecorationStream(Stream* stm) :stream(stm) {

    }
};

4. 代码实例

  其采用装饰模式修改的代码如下,可以看到,其代码量相当少,不会重写类的功能,其调用原本的类。

  

#include <stdio.h>
#include <iostream>
#include <windows.h>
using namespace std;

// 流基类
class Stream {
public:
    virtual void Read() = 0;
    virtual void Write() = 0;
    virtual ~Stream() {}
};

// 文件流
class FileStream :public Stream {
public:
    virtual void Read() {
        cout << "正在读取文件流..." << endl;
    }
    virtual void Write() {
        cout << "正在写入文件流..." << endl;
    }
};

// 内存流
class MemoryStream :public Stream {
public:
    virtual void Read() {
        cout << "正在读取内存流..." << endl;
    }
    virtual void Write() {
        cout << "正在写入内存流..." << endl;
    }
};

// 装饰器
class DecorationStream : public Stream {
public:
    Stream* stream;
    // 构造函数为流赋值
    DecorationStream(Stream* stm) :stream(stm) {

    }
};

// 加密操作
class CryptoStream :public DecorationStream {
public:
    CryptoStream(Stream* stm) :DecorationStream(stm) {

    }
    virtual void Read() {
        cout << "正在执行其加密读操作..." << endl;
        stream->Read();
    }
    virtual void Write() {
        cout << "正在执行加密写操作..." << endl;
        stream->Write();
    }
};

// 缓冲操作
class BufferStream :public DecorationStream {
public:
    BufferStream(Stream* stm) :DecorationStream(stm) {

    }
    virtual void Read() {
        cout << "正在执行缓冲读操作..." << endl;
        stream->Read();
    }
    virtual void Write() {
        cout << "正在执行缓冲写操作..." << endl;
        stream->Write();
    }
};

int main() {
    // 一般情况
    FileStream* f = new FileStream();
    f->Read();
    cout << "------------------" << endl;
    // 当该文件流需要加密时
    CryptoStream* Cf = new CryptoStream(f);
    Cf->Read();
    cout << "------------------" << endl;
    // 当既需要加密又需要缓冲操作时
    BufferStream* Bf = new BufferStream(Cf);
    Bf->Read();
}

 

  

猜你喜欢

转载自www.cnblogs.com/onetrainee/p/12732402.html