• [设计模式]装饰模式


    [设计模式]装饰模式

    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();
    }

     

      

  • 相关阅读:
    汉诺塔难题
    函数的两种调用方式

    汉诺塔难题
    汉诺塔难题

    python中对小数取整
    linux中部署apache服务(http服务或者web服务)
    python中如何判断变量类型
    python中求余数
  • 原文地址:https://www.cnblogs.com/onetrainee/p/12732402.html
Copyright © 2020-2023  润新知