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

介绍

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

实现

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;
}
相关推荐
爱学习的小王!14 分钟前
有关MyBatis的动态SQL
java·笔记·sql·学习·mybatis
一条晒干的咸魚23 分钟前
【C#学习笔记03】进制转换与反码、补码、原码
开发语言·笔记·学习·c#
王嘉俊9251 小时前
MySQL 入门笔记
数据库·笔记·sql·mysql·adb
你的微笑像拥抱1 小时前
npm-shrinkwrap.json 与 package-lock.json 区别和联系
笔记
niu_sama1 小时前
[杂学笔记] TCP和UDP的区别,对http接口解释 , Cookie和Session的区别 ,http和https的区别 , 智能指针 ,断点续传
笔记·tcp/ip·http
淳杰2 小时前
ubuntu-学习笔记-nginx+php
笔记·学习·ubuntu
阿噜噜小栈2 小时前
如何用AI制作我们记忆中的乡村夜景
人工智能·经验分享·笔记
Angindem2 小时前
RabbitMQ (Java)学习笔记
笔记·学习·rabbitmq
大白的编程日记.2 小时前
【Git学习笔记】Git初识及其结构原理分析(一)
笔记·git·学习
weixin_448119944 小时前
Datawhale coze-ai-assistant 笔记1
笔记