C++设计模式——Decorator装饰器模式

news2024/12/28 1:58:23

一,装饰器模式简介

装饰器模式是一种结构型设计模式, 它允许在不改变现有对象的情况下,动态地将功能添加到对象中。

装饰器模式是通过创建具有新行为的对象来实现的,这些对象将原始对象进行了包装。

装饰器模式遵循开放/关闭原则,允许开发者在不修改现有代码的情况下添加新的装饰器。

日常开发中常用的装饰器属于类装饰器,通过继承父类来实现。

二,装饰器模式的结构

1.抽象组件(Component):被装饰的对象,声明了对外的统一接口。

2.具体组件(ConcreteComponent):包含抽象组件接口的具体代码实现。

3.抽象装饰器(Decorator):包含对抽象组件的指针或引用,并定义了与抽象组件一致的接口。

4.具体装饰器(ConcreteDecorator):包含抽象装饰器接口的具体代码实现,并且可以在调用对外接口之前或之后添加额外的行为。

对应UML类图:

拿生活中举例:某硬核产品的可拆卸装饰

三,装饰器模式的工作步骤

1.创建抽象组件类,定义抽象组件的对外接口,将核心功能声明在该接口中。

2.创建具体组件类,继承抽象组件类,实现抽象组件类的接口。

3.创建抽象装饰器类,继承抽象组件类,实现抽象组件类的接口,并持有一个抽象组件对象的引用。

4.创建具体装饰器类,继承抽象装饰器类,在实现核心接口之后,添加额外的接口函数。

5.在客户端中使用装饰器包装抽象组件,并调用它们的方法。

四,装饰器模式代码样例

暂时不带具体装饰器ConcreteDecorator,直接在Decorator中添加额外功能。

#include <iostream>

class Component {
public:
    virtual void operation() = 0;
};

class ConcreteComponent : public Component {
public:
    void operation() override {
        std::cout << "From ConcreteComponent." << std::endl;
    }
};

class Decorator : public Component {
public:
    Decorator(Component& component):component_(component){}
    void operation() override {
        std::cout << "from Decorator." << std::endl;
        component_.operation();
    }

private:
    Component& component_;
};

int main() {
    ConcreteComponent concreteComponent;
    Decorator decoratedComponent(concreteComponent);
    decoratedComponent.operation();
    return 0;
}

运行结果:

from Decorator.
From ConcreteComponent.

五,装饰器模式的应用场景

组件扩展:在大型项目中,随着业务的增加,必定要添加新的功能,装饰器此时可以避免修改原有的基础组件。

API增强:当提供API给第三方进行调用时,装饰器可以用于添加额外的功能,比如日志记录、安全校验等,而调用者无需知道具体的细节。

权限管理:装饰器可以用来控制对原有的特定接口的访问权限。

缓存机制:在网络请求或数据库查询等操作中,装饰器可以用来添加额外的缓存、重试、超时处理等功能。

六,装饰器模式的优缺点

装饰器模式的优点:

1.可以动态地添加或删除对象的功能,无需修改原有的代码。

2.不影响现有对象的结构,符合开闭原则。

3.可以灵活地扩展原有对象的功能。

4.可以使用多个装饰器对象来组合多种功能。

5.使得代码可以根据需要轻松地添加或移除功能。

装饰器模式的缺点:

1.使系统中增加额外的类变量。

2.装饰器对象与原始对象之间的关系过于复杂,降低代码可读性。

七,代码实战

Demo1: 自助冰淇淋制作机

#include <iostream>
#include <string>

using namespace std;

// Component
class IceCream {
public:
    virtual string getDescription() const = 0;
    virtual double cost() const = 0;
};

// Concrete Component
class VanillaIceCream : public IceCream {
public:
    string getDescription() const override
    {
        return "Vanilla Ice Cream";
    }

    double cost() const override { return 160.0; }
};

// Decorator
class Decorator : public IceCream {
protected:
    IceCream* iceCream;

public:
    Decorator(IceCream* ic)
        : iceCream(ic)
    {
    }

    string getDescription() const override
    {
        return iceCream->getDescription();
    }

    double cost() const override
    {
        return iceCream->cost();
    }
};

// Concrete Decorator - adds chocolate topping.
class ChocolateDecorator : public Decorator {
public:
    ChocolateDecorator(IceCream* ic)
        : Decorator(ic)
    {
    }

    string getDescription() const override
    {
        return iceCream->getDescription()
            + " with Chocolate";
    }

    double cost() const override
    {
        return iceCream->cost() + 100.0;
    }
};

// Concrete Decorator - adds caramel topping.
class CaramelDecorator : public Decorator {
public:
    CaramelDecorator(IceCream* ic)
        : Decorator(ic)
    {
    }

    string getDescription() const override
    {
        return iceCream->getDescription() + " with Caramel";
    }

    double cost() const override
    {
        return iceCream->cost() + 150.0;
    }
};

int main()
{
    // Create a vanilla ice cream
    IceCream* vanillaIceCream = new VanillaIceCream();
    cout << "Order: " << vanillaIceCream->getDescription()
        << ", Cost: Rs." << vanillaIceCream->cost()
        << endl;

    // Wrap it with ChocolateDecorator
    IceCream* chocolateIceCream
        = new ChocolateDecorator(vanillaIceCream);
    cout << "Order: " << chocolateIceCream->getDescription()
        << ", Cost: Rs." << chocolateIceCream->cost()
        << endl;

    // Wrap it with CaramelDecorator
    IceCream* caramelIceCream
        = new CaramelDecorator(chocolateIceCream);
    cout << "Order: " << caramelIceCream->getDescription()
        << ", Cost: Rs." << caramelIceCream->cost()
        << endl;

    delete vanillaIceCream;
    delete chocolateIceCream;
    delete caramelIceCream;

    return 0;
}

运行结果:

Order: Vanilla Ice Cream, Cost: Rs.160
Order: Vanilla Ice Cream with Chocolate, Cost: Rs.260
Order: Vanilla Ice Cream with Chocolate with Caramel, Cost: Rs.410

Demo2: 模拟的绘图组件

#include <iostream>
using namespace std;

// Component
class Widget
{
public:
    virtual void draw() = 0;
};

// Concrete Component
class TextField : public Widget
{
    int width, height;
public:
    TextField(int w, int h)
    {
        width = w;
        height = h;
    }
    void draw()
    {
      cout << "TextField: " << width << "," << height;
    }
};

// Decorator
class Decorator : public Widget  
{
    Widget* wid;
public:
    Decorator(Widget* w)
    {
        wid = w;
    }
    void draw()
    {
        wid->draw();
    }
};

// Concrete Decorator
class BorderDecorator : public Decorator
{
public:
    BorderDecorator(Widget* w): Decorator(w){}
    void draw()
    {
        //基础功能
        Decorator::draw();
        //扩展功能
        cout << "\n BorderDecorator" ;
    }
};

// Concrete Decorator
class ScrollDecorator : public Decorator
{
public:
    ScrollDecorator(Widget* w): Decorator(w){}
    /*virtual*/
    void draw()
    {
        //基础功能
        Decorator::draw();
        //扩展功能
        cout << "\n ScrollDecorator";
    }
};
int main()
{
    Widget* aWidget = new BorderDecorator(
     new ScrollDecorator(new TextField(80, 24)));
    aWidget->draw();
}

运行结果:

TextField: 80,24
ScrollDecorator
BorderDecorator

八,参考阅读

https://www.pentalog.com/blog/design-patterns/decorator-design-pattern/

https://www.geeksforgeeks.org/introduction-to-decorator-pattern-in-c-design-patterns/

https://sourcemaking.com/design_patterns/decorator/cpp/2

https://sourcemaking.com/design_patterns/decorator

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1820898.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

对补码的理解:两种求法

课本的结论是&#xff1a;二进制数的最高位是符号位。符号位为 0 表示正数和 零 &#xff0c;符号位为 1 表示负数。 正数是原码反码补码都是一样的。负数的反码是&#xff1a;符号位不变&#xff0c;剩下位取反。 负数的补码是&#xff1a;符号位不变&#xff0c;剩下位取反&a…

u-boot(四)-顶层目录链接脚本文件(u-boot.lds)介绍

一&#xff0c;IMX6ULL映像文件 1&#xff0c;格式概述 对于IMX6ULL&#xff0c;烧写在EMMC、SD/TF卡上的程序&#xff0c;并不能“自己复制自己”&#xff0c;是“别人把它复制到内存里”。一上电首先运行的是boot ROM上的程序&#xff0c;它从EMMC、SD/TF卡上把程序复制进内…

妙用OSGraph:发掘GitHub知识图谱上的开源故事

作者&#xff1a;范志东 1. 何为OSGraph&#xff1f; OSGraph (Open Source Graph) 是一个开源图谱关系洞察工具&#xff0c;基于GitHub开源数据全域图谱&#xff0c;实现开发者行为、项目社区生态的分析洞察。可以为开发者、项目Owner、开源布道师、社区运营等提供简洁直观的…

电脑自带录屏在哪?电脑录屏,4个详细方法

在现代社会中&#xff0c;越来越多的人需要在电脑上录制视频&#xff0c;比如录制游戏操作、制作教学视频、演示文稿等等。因此&#xff0c;电脑录屏成为了一项非常重要的功能。那么电脑自带录屏在哪&#xff1f;本文将带领大家看看可以使用哪些方法进行录屏。 录屏方法一&…

SK海力士计划于2024年第四季度启动GDDR7大规模生产

SK海力士&#xff0c;作为HBM市场的领头羊&#xff0c;于6月13日宣布&#xff0c;公司目标于2024年第四季度开始其GDDR7芯片的大规模生产。 与此同时&#xff0c;美光科技在Computex展会上也宣布推出其GDDR7图形内存&#xff0c;目前正处于样品测试阶段。据AnandTech报道&#…

Python | Leetcode Python题解之第149题直线上最多的点数

题目&#xff1a; 题解&#xff1a; class Solution:def maxPoints(self, points: List[List[int]]) -> int:n len(points)if n < 2:return nres 2for i in range(n):x1, y1 points[i][0], points[i][1]has {}for j in range(i 1, n):x2, y2 points[j][0], points…

AI虚拟试穿技术:开启高保真、多场景、多样化服装组合的试穿应用

随着电子商务的快速发展,消费者对于在线购物体验的要求越来越高。特别是在服装领域,消费者渴望能够在购买前直观地了解服装的试穿效果。传统的虚拟试穿技术虽然已有一定的发展,但在不同场景下的高保真度和鲁棒性方面仍面临挑战。为此,我们研发了一种全新的AI虚拟试穿技术,…

当JS遇上NLP:开启图片分析的奇幻之旅

前言 在当今科技飞速发展的时代&#xff0c;JavaScript&#xff08;JS&#xff09;作为广泛应用的编程语言&#xff0c;展现出了强大的活力与无限的可能性。与此同时&#xff0c;自然语言处理&#xff08;NLP&#xff09;领域也正在经历着深刻的变革与进步。 当这两者碰撞在一…

探索AI视频生成技术的原理

探索AI视频生成技术的原理 随着人工智能技术的迅猛发展&#xff0c;AI在视频生成领域的应用已经引起了广泛关注。从娱乐、广告到教育和科学研究&#xff0c;AI视频生成技术正在彻底改变我们制作和消费视频内容的方式。本文将深入探讨AI视频生成技术的原理&#xff0c;解析其背…

解决CentOS的yum命令失效的问题

近日笔者对一台装有 CentOS 7.9 系统的服务器反复折腾&#xff0c;玩到最后发现 yum 命令用不了&#xff0c;总是报下面的错误信息&#xff1a; There was a problem importing one of the Python modules required to run yum. The error leading to this problem was:/usr/l…

通用大模型VS垂直大模型,你更青睐哪一方?

AI大模型之辩&#xff1a;通用与垂直&#xff0c;谁将引领未来&#xff1f; 在人工智能&#xff08;AI&#xff09;领域&#xff0c;大模型技术的崛起无疑为整个行业带来了革命性的变革。然而&#xff0c;随着技术的深入发展&#xff0c;AI大模型的战场似乎正在悄然分化&#…

9.常见集合

目录 一、三种常见集合二、Vector2.1 特性2.2 创建并更新Vector2.3 读取Vector中的元素2.4 遍历元素2.5 储存不同类型的值 三、字符串3.1 概念3.2 新建3.2 更新3.3 索引字符串3.4 字符串切片3.5 字符串遍历 四、哈希map4.1 基本概念4.2 新建哈希map4.3 访问哈希map中的值4.4 更…

使用adb通过wifi连接手机

1&#xff0c;手机打开开发者模式&#xff0c;打开无线调试 2&#xff0c;命令行使用adb命令配对&#xff1a; adb pair 192.168.0.102:40731 输入验证码&#xff1a;422859 3&#xff0c;连接设备&#xff1a; adb connect 192.168.0.102:36995 4&#xff0c;查看连接状态:…

【云岚到家】-day03-2-门户缓存实现实战

【云岚到家】-day03-2-门户缓存实现实战 5 缓存实现5.2 定时任务更新缓存5.2.1 分布式调度平台5.2.1.1 jdk提供的Timer定时器5.2.1.2 使用第三方Quartz方式5.2.1.3 使用分布式调度平台XXL-JOB 5.2.2 XXL-JOB5.2.2.1 介绍5.2.2.2 部署调度中心5.2.2.3 执行器 5.2.2 定义缓存更新…

二开版视频CMS完整运营源码/新版漂亮APP手机模板/集成员分销功能等

一个二开的影视CMS&#xff0c;直接上传源码至网站根目录&#xff0c;访问网站域名即可安装。 测试环境&#xff1a;Nginx 1.20.1—MySQL 5.6.50–PHP-7.2&#xff08;安装拓展/fileinfo&#xff09; 上传源码&#xff0c;访问域名直接安装 后台地址&#xff1a;域名/MDadmi…

4. 案例研究-接口程序

4. 案例研究-接口程序 本章通过一个案例研究, 来展示设计互相配合的函数的过程.4.1 turtle 模块 创建一个文件mypolygon.py, 并输入如下代码:import turtle bob turtle.Turtle() print(bob)# 这一句的作用是让画板停留, 等手动点击x关闭画板, 程序才结束. # 否则程序执行完毕…

Spring中的IOC

IOC&#xff08;Inversion of Control&#xff0c;控制反转&#xff09;是Spring框架核心概念之一。它是一种设计原则&#xff0c;用来实现对象的松耦合和依赖管理。在传统的编程中&#xff0c;对象负责创建或查找其依赖对象&#xff0c;而在IOC模式下&#xff0c;这些职责被移…

C++ | Leetcode C++题解之第150题逆波兰表达式求值

题目&#xff1a; 题解&#xff1a; class Solution { public:int evalRPN(vector<string>& tokens) {int n tokens.size();vector<int> stk((n 1) / 2);int index -1;for (int i 0; i < n; i) {string& token tokens[i];if (token.length() >…

24年大一尺取练习(东北林业大学)

前言&#xff1a; 今天下午才刚看到oj上发了这次练习&#xff0c;我已经错过了截止时间&#xff0c;刚好不是很想复习六级&#xff0c;就把这次练习补了吧。 正文&#xff1a; Problem:A 尺取Language&#xff1a; #include<bits/stdc.h> using namespace std; const i…

如何把路由器设备的LAN口地址为三大私网地址

要将路由器的LAN口地址配置为三大私有IP地址范围之一&#xff08;10.0.0.0/8、172.16.0.0/12 或 192.168.0.0/16&#xff09;&#xff0c;我们需要访问路由器的管理界面并进行相应的设置。 下面是步骤&#xff1a; 连接到路由器&#xff1a; 连接到路由器的管理界面&#xf…