深入浅出设计模式 - 装饰者模式

news2025/1/10 23:33:41

博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌

Java知识图谱点击链接:体系化学习Java(Java面试专题)

💕💕 感兴趣的同学可以收藏关注下不然下次找不到哟💕💕

在这里插入图片描述

文章目录

  • 1、什么是装饰者模式
  • 2、装饰者模式的优缺点
  • 3、装饰者模式的应用场景
  • 4、装饰者模式的结构
  • 5、装饰者模式的代码案例

1、什么是装饰者模式

装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你向一个现有的对象添加新的功能,同时又不改变其结构。装饰者模式基于组合而非继承的原则,它动态地将责任附加到对象上。

装饰者模式涉及到四个角色:抽象组件、具体组件、抽象装饰者和具体装饰者。其中,抽象组件定义了组件的基本功能,具体组件实现了组件的基本功能,抽象装饰者定义了装饰者的基本功能,具体装饰者实现了装饰者的基本功能,并且可以添加额外的功能。

装饰者模式的优点是可以动态地添加或删除对象的功能,而不需要修改现有的代码。它还可以避免使用子类来扩展对象的功能,从而减少类的数量。缺点是装饰者模式会增加许多小对象,从而增加系统的复杂性。

2、装饰者模式的优缺点

装饰者模式的优点包括:

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

  2. 可以避免使用子类来扩展对象的功能,从而减少类的数量。

  3. 可以将多个装饰者组合起来,实现更复杂的功能。

装饰者模式的缺点包括:

  1. 装饰者模式会增加许多小对象,从而增加系统的复杂性。

  2. 装饰者模式可能会导致设计变得过于抽象,从而难以理解和维护。

  3. 装饰者模式可能会影响程序的性能,因为每个装饰者都会增加额外的处理时间。

3、装饰者模式的应用场景

装饰者模式通常适用于以下场景:

  1. 在不影响现有对象结构的情况下,动态地添加额外的功能或行为。

  2. 需要扩展一个类的功能,但是使用继承会导致类的数量增加,且不利于维护。

  3. 需要在不修改代码的情况下,对对象的某些功能进行组合或移除。

  4. 需要对一个对象的功能进行多次扩展或组合,而不是一次性地进行全部扩展或组合。

  5. 需要在运行时动态地添加或删除对象的功能。

  6. 需要在不破坏封装性的前提下,对对象的功能进行扩展或修改。

  7. 需要对对象的功能进行动态排序或过滤。

  8. 需要对对象的功能进行动态配置或组合。

总之,装饰者模式适用于需要动态地添加或删除对象的功能,同时又不希望对现有对象结构进行修改的场景。

4、装饰者模式的结构

装饰者模式的结构包括以下组件:

  1. 抽象组件(Component):定义了组件的接口,可以是抽象类或接口。

  2. 具体组件(Concrete Component):实现了抽象组件的接口,提供了基本的功能。

  3. 抽象装饰者(Decorator):定义了装饰者的接口,包含一个指向抽象组件的引用。

  4. 具体装饰者(Concrete Decorator):实现了抽象装饰者的接口,对抽象组件添加了新的功能。

装饰者模式使用组合而非继承的方式,动态地将责任附加到对象上,从而实现了动态地扩展对象的功能。它可以在不修改现有代码的情况下,动态地添加或删除对象的功能,同时避免了使用子类来扩展对象的功能,从而减少了类的数量。

5、装饰者模式的代码案例

假设有一个饮料类(Beverage),它有一个描述(description)和一个计算价格(cost)的方法。现在需要给这个饮料类添加一些调料(Condiment),比如牛奶、摩卡等,这些调料也有自己的描述和价格。使用装饰者模式,可以动态地添加或删除调料,而不需要修改饮料类的代码。

首先,我们定义一个饮料类Beverage,它是一个抽象类,包含描述和计算价格两个方法:

package com.pany.camp.design.principle.decorators;

/**
 *
 * @description: 抽象类
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-27 20:37
 */
public abstract class Beverage {
    String description = "Unknown Beverage";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

然后,我们定义一个具体的饮料类Espresso,它继承自Beverage类,实现了cost方法和description属性:

package com.pany.camp.design.principle.decorators;

/**
 *
 * @description:  抽象实现
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 20:38
 */
public class Espresso extends Beverage {
    public Espresso() {
        description = "Espresso";
    }
    public double cost() {
        return 1.99;
    }
}

接下来,我们定义一个抽象的调料类CondimentDecorator,它也是一个抽象类,继承自Beverage类,包含一个抽象的getDescription方法:

package com.pany.camp.design.principle.decorators;

/**
 *
 * @description:  抽象的调料类
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 20:38
 */
public abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}

然后,我们定义一个具体的调料类Milk,它继承自CondimentDecorator类,包含一个Beverage类型的成员变量和一个构造方法,用于接收一个饮料对象,然后将其保存到成员变量中。getDescription方法会调用Beverage对象的getDescription方法,并在其后面添加", Milk"。cost方法会调用Beverage对象的cost方法,并加上0.10的价格:

package com.pany.camp.design.principle.decorators;

/**
 *
 * @description:  具体的调料类Milk
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 20:39
 */
public class Milk extends CondimentDecorator {
    Beverage beverage;

    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }

    public String getDescription() {
        return beverage.getDescription() + ", Milk";
    }

    public double cost() {
        return beverage.cost() + 0.10;
    }
}

类似地,我们定义另一个具体的调料类Mocha,它也继承自CondimentDecorator类,包含一个Beverage类型的成员变量和一个构造方法,用于接收一个饮料对象,然后将其保存到成员变量中。getDescription方法会调用Beverage对象的getDescription方法,并在其后面添加", Mocha"。cost方法会调用Beverage对象的cost方法,并加上0.20的价格:

package com.pany.camp.design.principle.decorators;

/**
 *
 * @description:  具体的调料类Mocha
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-27 20:40 
 */
public class Mocha extends CondimentDecorator {
    Beverage beverage;

    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }

    public String getDescription() {
        return beverage.getDescription() + ", Mocha";
    }

    public double cost() {
        return beverage.cost() + 0.20;
    }
}

最后,我们可以使用如下的测试代码来测试我们的装饰者模式:

package com.pany.camp.design.principle.decorators;

/**
 * @description: 客户端
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-27 20:40
 */
public class Client {

    public static void main(String[] args) {
        Beverage beverage = new Espresso();
        System.out.println(beverage.getDescription() + " $" + beverage.cost());
        beverage = new Milk(beverage);
        System.out.println(beverage.getDescription() + " $" + beverage.cost());
        beverage = new Mocha(beverage);
        System.out.println(beverage.getDescription() + " $" + beverage.cost());
    }
}

输出结果为:

Espresso $1.99
Espresso, Milk $2.09
Espresso, Milk, Mocha $2.29

Process finished with exit code 0

可以看到,通过装饰者模式,我们动态地给饮料类添加了调料,而不需要修改饮料类的代码。
在这里插入图片描述

💕💕 本文由激流原创,首发于CSDN博客,博客主页 https://blog.csdn.net/qq_37967783?spm=1010.2135.3001.5421
💕💕喜欢的话记得点赞收藏啊
在这里插入图片描述

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

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

相关文章

Python桌面应用开发之PyQt

文章目录 引言:桌面应用开发三大框架介绍一、PyQT介绍二、安装三、使用教程(1)基础窗口(2)分区布局窗口(类似于html中div的使用)(3)栅格布局窗口(类似于html中的table)(4)表单布局窗口(类似于html中的form)(5)事件函数与事件过滤器(6)信号和槽四、实战示例(1)状态栏…

跨链协议悄然升级

当前加密产业公链百家争鸣,群雄割据,每条公链都拥有自身的忠实用户。 然而,公链与公链之间仿佛一座座孤岛,无法进行无缝的交流和联系,仅能通过跨链桥经由在两条不同的链上运用不同处理机制来协助转移用户的资产。但&a…

【深度学习 | CNN】“深入解析卷积神经网络与反卷积:从原理到应用的全面指南” (从一维、二维、三维讲解)

🤵‍♂️ 个人主页: @AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨‍💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!🐱‍🏍 🙋‍♂️声明:本人目前大学就读于大二,研究兴趣方向人工智能&硬件(虽然硬件还没开始玩…

MySQL数据库的MHA高可用集群部署及故障切换(图文详解!绝对详细!!)

目录 一、MHA概述 1、MHA简介 2、MHA 的组成 (1)MHA Node(数据节点) (2)MHA Manager(管理节点) 3、MHA 的特点 二、 搭建MySQLMHA 1、实验思路 2、修改mysql节点的主机名 3&…

JS 事件委托

JavaScript事件委托(Event delegation)又叫事件代理,是一种在父元素上监听事件,然后通过事件冒泡机制来处理子元素的事件的技术。通过事件委托,可以避免为每个子元素都绑定事件处理程序,提高性能并简化代码…

SC7504运算放大器(OPA)可pin对pin兼容OPA4350

SC750x 系列轨至轨 CMOS 运算放大器针对低电压单电源运行进行了优化。轨至轨输入和输出、低噪声(5nV/√Hz) 和高速运行(38MHz, 22V/μs) 使得运算放大器非常适合驱动模数 (A/D) 转换器。可pin对pin兼容OPA4350。而且也适用于手机功率放大器 (PA) 控制环路和视频处理&#xff08…

【嵌入式Qt开发入门】初识Qt——Linux下安装Qt

Qt 是什么? Qt 是一个跨平台的 C开发库。主要用来开发图形用户界面(Graphical User Interface,简 称 GUI)程序。 Qt 虽然经常被当做一个 GUI 库,用来开发图形界面应用程序,但这并不是 Qt 的全部&#xff1b…

Win11总是出现BitLocker恢复,想要彻底关闭它该如何操作?

win11解除bitlocker加密方法一: 1、首先按下键盘“WinR”打开运行(如图所示)。 2、打开运行后,在其中输入“control”并点击“确定”打开控制面板(如图所示)。 3、打开后,进入“bitlocker驱动器加密”(如图所示)。 4、随后展开被加密的磁盘&…

Pycharm报错Non-zero exit code (2)

问题现象: 通常我们拿到一个Python项目后,项目中有requirement.txt文件,里面有列出需要安装的三方库,使用pycharm直接安装这些库时,报错:Non-zero exit code (2) 解决方案: 第一种临时解决方案&…

模糊图片秒转高清图,分享几个免费方法!

相信大家都曾经遇到过拍摄的老旧照片放大后变得模糊不清的情况。然而,由于这些照片是我们自己拍摄的,我们也无法在网上找到并下载原始高清图像。那么,有没有什么方法可以修复这种模糊不清的照片呢?当然,很多人可能会说…

计算机硬件

硬盘 固态硬盘(SSD)拥有比机械硬盘(HDD)更快的读写速度。目前大多数机器使用的是SATA总线标准,实际最高传输约为600MB/s。而支持PCIe总线,NVMe协议的SSD,实际传输速度将超过1000MB/s。 当前采…

KDG5V-8-33C330N200-EX-H-M-U-H1-20比例方向阀控制器

与外置电子放大器一起使用,在智能控制系统和液压系统之间提供接口。这是一种非常实用的方法,用于控制执行器的方向和速度,同时消除了机器负载的快速加速和减速所引起的冲击。除了提高机器的性能和寿命外,通过将方向和流量控制能力…

【UE5 Cesium】04-Cesium for Unreal 将不同地区的倾斜摄影作为不同子关卡

上一篇:【UE5 Cesium】03-Cesium for Unreal 添加本地数据集 步骤 1. 新建一个空白关卡 保存新建的关卡,命名为“Globe” 添加地图 再添加“Cesium SunSky”和“DynamicPawn” 在大纲中选中“Globe(编辑器)”,然后勾…

深入浅出设计模式 - 享元模式

博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌ Java知识图谱点击链接:体系化学习Java(Java面试专题) 💕💕 感兴趣的同学可以收…

初始Git

文章目录 前言技术目标协作目标 一、提出问题二、如何解决版本控制器注意事项 三、Git安装Linux-centosLinux-ubuntu 四、Git基本操作创建Git本地仓库配置Git 总结 前言 技术目标 掌握Git企业级应用,深刻理解Git操作过程与操作原理,理解工作区,暂存区,版本库的含义.掌握Git版…

LC-1595. 连通两组点的最小成本(状态压缩DP(记忆化搜索==>动态规划))

1595. 连通两组点的最小成本 难度困难86 给你两组点,其中第一组中有 size1 个点,第二组中有 size2 个点,且 size1 > size2 。 任意两点间的连接成本 cost 由大小为 size1 x size2 矩阵给出,其中 cost[i][j] 是第一组中的点 …

FineReport学习3

冻结行列(冻结表头) 创建多数据源之间的关联 给单元格添加过滤条件,让 ds2 的「客户ID」等于 ds1 的「客户ID」,这样两数据集就关联起来 复杂多源报表

.NETCore项目在Windows下构建Docker镜像并本地导出分发到CentOS系统下

在Windows下使用Docker,我们选择Docker Desktop这个软件,非常方便。 Docker Desktop介绍及安装 Docker Desktop是适用于Mac、Linux或Windows环境的一键安装应用程序,使您能够构建和共享容器化应用程序和微服务。 它提供了一个简单的GUI&…

[数据库系统] 五、数据增删改

第一关:数据插入 用insert给数据库添加数据 相关知识 有关系student(sno,sname,ssex,sage,sdept),属性对应含义:学号,姓名,性别,所在系。现有的部分元组如下所示 insert 向数据库表插入数据的基本格式有…

生成 ocr key 字符集 alphabet 6698个字符

生成 ocr key 字符集 alphabet import pickle as pkl#----------- 生成 ocr key 字符集 alphabet alphabet_set set() # 数据集label infofiles_label [/home/jlb/下载/rec_data_lesson_demo/train.txt, /home/jlb/下载/rec_data_lesson_demo/val.txt]# ppocr中文key infofil…