• 09 C++设计模式之装饰(Decorator)模式


    装饰模式定义

    装饰是一种结构型设计模式,允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为

    装饰模式优缺点

    优点

    • 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
    • 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
    • 装饰器模式完全遵守开闭原则

    缺点

    *装饰器模式会增加许多子类,过度使用会增加程序得复杂性

    装饰模式构成与实现

    构成

    • 具体部件(Concrete Component)类是被封装对象所属的类。它定义了基础行为,但装饰类可以改变这些行为。
    • 基础装饰(Base Decorator)类拥有一个指向被封装对象的引用成员变量。该变量的类型应当被声明为通用部件接口,这样它就可以引用具体的部件和装饰。装饰基类会将所有操作委派给被封装的对象。
    • 具体装饰类(Concrete Decorators) 定义了可动态添加到部件的额外行为。具体装饰类会重写装饰基类的方法,并在调用父类方法之前或之后进行额外的行为。
    • 客户端(Client)可以使用多层装饰来封装部件, 只要它能使用通用接口与所有对象互动即可。

    实例

    Component.h:

    #ifndef COMPONENT_H_
    #define COMPONENT_H_
    
    #include 
    
    // 部件: 是具体部件和装饰类的共同基类, 在C++中实现成抽象基类
    class DataSource {
     public:
        virtual void writeData(std::string data) = 0;
    };
    
    #endif  // COMPONENT_H_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    BaseDecorator.h:

    #ifndef BASE_DECORATOR_H_
    #define BASE_DECORATOR_H_
    
    #include 
    #include "Component.h"
    
    // 装饰基类和其他组件遵循相同的接口。该类的主要任务是定义所有具体装饰的封装接口。
    // 封装的默认实现代码中可能会包含一个保存被封装组件的成员变量,并且负责对其进行初始化。
    class DataSourceDecorator : public DataSource {
     public:
        explicit DataSourceDecorator(DataSource* ds) : data_source_(ds) {}
        void writeData(std::string data) override {
            data_source_->writeData(data);
        }
    
     protected:
        DataSource* data_source_;  // component
    };
    
    #endif  // BASE_DECORATOR_H_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    ConcreteComponent.h:

    #ifndef CONCRETE_COMPONENT_H_
    #define CONCRETE_COMPONENT_H_
    
    #include 
    #include 
    #include 
    #include "Component.h"
    
    // 具体组件提供操作的默认实现, 这些类在程序中可能会有几个变体
    class FileDataSource : public DataSource {
     public:
        explicit FileDataSource(std::string file_name) : file_name_(file_name) {}
        void writeData(std::string data) override {
            printf("写入文件%s中: %s\n", file_name_.c_str(), data.c_str());
            return;
        }
    
     private:
        std::string file_name_;
    };
    
    #endif  // CONCRETE_COMPONENT_H_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ConcreteDecorator.h:

    #ifndef CONCRETE_DECORATOR_H_
    #define CONCRETE_DECORATOR_H_
    
    #include 
    #include "BaseDecorator.h"
    
    // 加密装饰器
    class EncryptionDecorator : public DataSourceDecorator {
     public:
        using DataSourceDecorator::DataSourceDecorator;
        void writeData(std::string data) override {
            // 1. 对传递数据进行加密(这里仅简单实现)
            data = "已加密(" + data + ")";
            // 2. 将加密后数据传递给被封装对象 writeData(写入数据)方法
            data_source_->writeData(data);
            return;
        }
    };
    
    // 压缩装饰器
    class CompressionDecorator : public DataSourceDecorator {
     public:
        using DataSourceDecorator::DataSourceDecorator;
        void writeData(std::string data) override {
            // 1. 对传递数据进行压缩(这里仅简单实现)
            data = "已压缩(" + data + ")";
            // 2. 将压缩后数据传递给被封装对象 writeData(写入数据)方法
            data_source_->writeData(data);
            return;
        }
    };
    
    #endif  // CONCRETE_DECORATOR_H_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    main.cpp:

    #include "ConcreteComponent.h"
    #include "ConcreteDecorator.h"
    
    int main() {
    
        system("chcp 65001");
        FileDataSource* source1 = new FileDataSource("stdout");
    
        // 将明码数据写入目标文件
        source1->writeData("tomocat");
    
        // 将压缩数据写入目标文件
        CompressionDecorator* source2 = new CompressionDecorator(source1);
        source2->writeData("tomocat");
    
        // 将压缩且加密数据写入目标文件
        EncryptionDecorator* source3 = new EncryptionDecorator(source2);
        source3->writeData("tomocat");
    
        delete source1;
        delete source2;
        delete source3;
        system("pause");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    Java语法基础案例
    useEffect(fn, []) 不等于 componentDidMount()
    Spring Boot+Vue3前后端分离实战wiki知识库系统之分类管理功能开发
    flutter_学习记录_02底部 Tab 切换保持页面状态的几种方法
    ModStartBlog v8.2.0 独立友情链接页面,博客列表样式优化
    《C++ Primer》学习笔记
    (三)JPA - EntityManager的使用
    Python数据采集与处理之网页爬取
    学习java之前端知识掌握Day004
    24/8/9算法笔记 决策树VS线性回归
  • 原文地址:https://blog.csdn.net/qq_45531502/article/details/125618911