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

介绍

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

实现

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;
}
相关推荐
ThetaarSofVenice14 分钟前
能省一点是一点 - 享元模式(Flyweight Pattern)
java·设计模式·享元模式
记得多喝水o14 分钟前
图解设计模式
设计模式
InSighT__16 分钟前
设计模式与游戏完美开发(2)
java·游戏·设计模式
羊村懒哥31 分钟前
tomcat-安装笔记(包含虚拟主机配置)
java·笔记·tomcat
思忖小下1 小时前
梳理你的思路(从OOP到架构设计)_设计模式Android + Composite模式
设计模式·composite模式
silver6871 小时前
单例模式详解
设计模式
qq_430583971 小时前
QT笔记- QTreeView + QFileSystemModel 当前位置的保存与恢复 #选中 #保存当前索引
开发语言·笔记·qt
小王爱吃月亮糖2 小时前
QT-QVariant类应用
开发语言·c++·笔记·qt·visual studio
红色的山茶花2 小时前
YOLOv9-0.1部分代码阅读笔记-hubconf.py
笔记·深度学习·yolo
无涯学徒19982 小时前
J9学习打卡笔记
笔记·学习