《设计模式的艺术》笔记 - 装饰模式

介绍

装饰模式动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。

实现

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <vector>

class Component {   // 抽象构件
public:
    virtual void display();
};

class ConcreteComponent : public Component {    // 具体构件
public:
    void display() override;
};

class Decorator : public Component {   // 抽象装饰类
public:
    Decorator(Component *component);
    virtual void display();

private:
    Component *m_component;
};

class ConcreteDecorator : public Decorator {    // 具体装饰类
public:
    ConcreteDecorator(Component *component);

    void display() override;

private:
    void addedBehavior();
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"

void Component::display() {
    std::cout << "Component::display()" << std::endl;
}

void ConcreteComponent::display() {
    std::cout << "ConcreteComponent::display()" << std::endl;
}

Decorator::Decorator(Component *component) {
    m_component = component;
}

void Decorator::display() {
    m_component->display();
}

ConcreteDecorator::ConcreteDecorator(Component *component) : Decorator(component) {

}

void ConcreteDecorator::display() {
    Decorator::display();
    addedBehavior();
}

void ConcreteDecorator::addedBehavior() {
    std::cout << "增加新的操作" << std::endl;
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    Component *component = new ConcreteComponent();
    Decorator *decorator = new ConcreteDecorator(component);
    decorator->display();
    delete component;
    delete decorator;

    return 0;
}

总结

优点

  1. 对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。

  2. 可以通过一种动态的方式来扩展一个对象的功能。通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为。

  3. 可以对一个对象进行多次装饰。通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,得到功能更为强大的对象。

  4. 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,原有类库代码无须改变,符合开闭原则。

缺点

  1. 使用装饰模式进行系统设计时将产生很多小对象。这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同。大量小对象的产生势必会占用更多的系统资源,在一定程度上影响程序的性能。

  2. 装饰模式提供了一种比继承更加灵活机动的解决方案,但同时也意味着比继承更加易于出错,排错也很困难。对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

适用场景

  1. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

  2. 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式。不能采用继承的情况主要有两类:第1类是系统中存在大量独立的扩展,为支持每一种扩展或者扩展之间的组合将产生大量的子类,使得子类数目呈爆炸性增长;第2类是因为类已定义为不能被继承。

练习

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <vector>

class SimpleEncrypt {   // 具体构件类
public:
    virtual void encrypt(std::string &in, std::string &out);
};

class EncryptDecorator : public SimpleEncrypt {   // 抽象装饰类
public:
    EncryptDecorator(SimpleEncrypt *encypt);
    virtual void encrypt(std::string &in, std::string &out) override;

private:
    SimpleEncrypt *m_encrypt;
};


class ReverseEncrypt : public EncryptDecorator {    // 具体装饰类
public:
    ReverseEncrypt(SimpleEncrypt *encrypt);

    void encrypt(std::string &in, std::string &out) override;

private:
    void reverseEncrypt(std::string &in, std::string &out);
};

class ModEncrypt : public EncryptDecorator {    // 具体装饰类
public:
    ModEncrypt(SimpleEncrypt *encrypt);

    void encrypt(std::string &in, std::string &out) override;

private:
    void modEncrypt(std::string &in, std::string &out);
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"

void SimpleEncrypt::encrypt(std::string &in, std::string &out) {
    std::cout << "执行简单加密" << std::endl;
    out = "简单加密+" + in;
}

EncryptDecorator::EncryptDecorator(SimpleEncrypt *encypt) {
    m_encrypt = encypt;
}

void EncryptDecorator::encrypt(std::string &in, std::string &out) {
    m_encrypt->encrypt(in, out);
}

ReverseEncrypt::ReverseEncrypt(SimpleEncrypt *encrypt) : EncryptDecorator(encrypt) {
}

void ReverseEncrypt::encrypt(std::string &in, std::string &out) {
    std::string tmp;
    EncryptDecorator::encrypt(in, tmp);
    reverseEncrypt(tmp, out);
}

void ReverseEncrypt::reverseEncrypt(std::string &in, std::string &out) {
    std::cout << "执行逆向加密" << std::endl;
    out = "逆向加密+" + in;
}

ModEncrypt::ModEncrypt(SimpleEncrypt *encrypt) : EncryptDecorator(encrypt) {

}

void ModEncrypt::encrypt(std::string &in, std::string &out) {
    std::string tmp;
    EncryptDecorator::encrypt(in, tmp);
    modEncrypt(tmp, out);
}

void ModEncrypt::modEncrypt(std::string &in, std::string &out) {
    std::cout << "执行取模加密" << std::endl;
    out = "取模加密+" + in;
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    std::string data = "data";
    std::string result;

    SimpleEncrypt *sim = new SimpleEncrypt();
    sim->encrypt(data, result);
    std::cout << "result:" << result << std::endl;

    EncryptDecorator *res = new ReverseEncrypt(sim);
    res->encrypt(data, result);
    std::cout << "result:" << result << std::endl;

    EncryptDecorator *mod = new ModEncrypt(res);
    mod->encrypt(data, result);
    std::cout << "result:" << result << std::endl;

    delete mod;
    delete res;
    delete sim;

    return 0;
}
相关推荐
xian_wwq6 分钟前
【学习笔记】威胁情报
网络·笔记·学习
小糊涂加油11 分钟前
TypeScript学习笔记
笔记·学习
@游子13 分钟前
Python学习笔记-Day6
笔记·python·学习
xunyan623419 分钟前
面向对象(下)-模版方法的设计模式其应用场景
java·学习·设计模式
四维碎片37 分钟前
【Qt】QTimer 学习笔记总结
笔记·qt·学习
每天努力学编程1 小时前
磁盘分区扩容笔记
笔记
Mr_Hu4041 小时前
鸿蒙开发学习笔记-生命周期小记
笔记·学习·harmonyos·鸿蒙
此剑之势丶愈斩愈烈1 小时前
设计模式学习
学习·设计模式
摇滚侠1 小时前
2025最新 SpringCloud 教程,Gateway-过滤器-基本使用,笔记58
笔记·spring cloud·gateway
阿恩.7701 小时前
2026年2月最新国际会议分享,含计算机/教育/工程技术/电力能源/数学~
人工智能·经验分享·笔记·计算机网络·数学建模·能源