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

介绍

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

实现

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;
}
相关推荐
Starry_hello world1 小时前
二叉树实现
数据结构·笔记·有问必答
唐·柯里昂7988 小时前
[3D打印]拓竹切片软件Bambu Studio使用
经验分享·笔记·3d
sml_54218 小时前
【笔记】连续、可导、可微的概念解析
笔记·线性代数
新手unity自用笔记8 小时前
项目-坦克大战学习-子弹的移动与销毁
笔记·学习·c#
Word码8 小时前
数据结构:栈和队列
c语言·开发语言·数据结构·经验分享·笔记·算法
我命由我123459 小时前
SSL 协议(HTTPS 协议的关键)
网络·经验分享·笔记·学习·https·ssl·学习方法
丶Darling.9 小时前
代码随想录 | Day26 | 二叉树:二叉搜索树中的插入操作&&删除二叉搜索树中的节点&&修剪二叉搜索树
开发语言·数据结构·c++·笔记·学习·算法
结衣结衣.10 小时前
python中的函数介绍
java·c语言·开发语言·前端·笔记·python·学习
LN-ZMOI11 小时前
c++学习笔记1
c++·笔记·学习
qq_4218336711 小时前
计算机网络——应用层
笔记·计算机网络