【设计模式】装饰器模式( Decorator Pattern)

news2025/7/21 10:49:54

装饰器模式属于结构型模式,主要解决当系统需要添加新功能,需要向旧类中不断添加新的属性和方法,从而导致整个类的复杂度不断增长的问题。假如新加的代码仅仅是为了满足特定场景下才会执行的需要,那么就没必要全部写在主类中,此时就可以使用装饰模式来解决,把要装饰的代码写在新加的类中,在需要的时候动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

文章目录

  • 装饰器模式的介绍
    • 优点
    • 缺点
    • 应用场景
  • 装饰器模式的使用
    • 类图
      • 装饰器中存在四个角色
    • 实现方法
      • 第一步,编写具体构建角色(机甲类)
      • 第二步,编写抽象装饰角色(外设类)
      • 第三步,编写具体装饰角色(钛合金装甲等模块)
      • 第四步,编写测试类测试
  • 本文参考


装饰器模式的介绍

​ 装饰器(Decorator)模式也可叫包装模式(Wrapper Pattern) ,是为已有功能动态添加更多功能的一种方式。装饰器通过新建装饰类,用来包装原有的类,在保证原有类结构完整的情况下添加新功能。此模式将原有类当做组件,或者为原有类新建一个抽象类当做组件接口,原有类和装饰类通过继承该抽象类来实现关联。当需要使用装饰功能时只需要让装饰类包装原有类的对象即可完成装饰。

优点

  • 装饰器是继承的有力补充,它比继承灵活,在不改变原有对象的情况下,能够动态的给一个对象扩展功能
  • 有效的将类的核心功能和装饰功能分离,去除相关类中重复的装饰逻辑
  • 装饰类和被装饰类解耦,可以独立修改扩展
  • 通过使用不同装饰类与被装饰类组合,实现不同的功能实现
  • 符合开闭原则

缺点

  • 装饰类通过添加新的子类来实现新的功能,到后期可能会出现大量装饰子类,增加复杂性
  • 多层装饰会导致程序层次更复杂

应用场景

  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时

  • 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类

  • 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰器模式却很好实现

  • 在Java IO中 OutputStream 就具备多个装饰子类,如 ByteArrayOutputStreamObjectOutputStreamFileOutputStream等都是对输出流功能的扩展。



装饰器模式的使用

例子:可恶的怪物正在践踏我们的家园!万幸科学家们已经完成了对机甲(被装饰类)的研制工作,工程师们也为机甲设计了多套强大的扩展装甲(装饰类),是时候组装我们的最强机甲了,把那些怪物溺死在太平洋吧!

类图

装饰器中存在四个角色

  • 抽象构件(Component)角色:该角色定义一个抽象接口以规范准备接收额外责任的对象,但我的例子中因为只有一个机甲,所以不需要设置该角色

  • 具体构件(Concrete Component)角色:实现抽象构件,通过装饰该角色来为其添加一些额外的职责,对应上方的机甲类

  • 抽象装饰(Decorator)角色:该角色继承抽象构件,为抽象类,类中持有具体构件的实例,以此达到通过其子类扩展具体构件职责的功能,对应上方外设类

  • 具体装饰(Concrete Decorator)角色:实现抽象装饰角色的相关方法,以此给具体构件对象添加附加的责任


实现方法


第一步,编写具体构建角色(机甲类)

机甲类

package 设计模式.结构型模式.装饰器模式;

/**
 * 具体构件角色,因为本案例只有一个具体构件,所以不需要设置抽象构件来约束构件角色
 */
public class 机甲类 {

    public void 展示(){
        System.out.println("机甲开始组装……组装完毕!");
    }
}

第二步,编写抽象装饰角色(外设类)

外设类

package 设计模式.结构型模式.装饰器模式;

/**
 * 抽象装饰角色,约束具体装饰类的方法
 */
public abstract class 外设类 extends 机甲类 {

    protected 机甲类 待装机甲;

    public 外设类(机甲类 待装机甲){
        // 持有被装饰类,通过聚合关系达到被装饰类与装饰类的组合
        this.待装机甲 = 待装机甲;
    }
    
    // 规定具体装饰类通过该方法来对被装饰类的功能进行扩展
    public abstract void 展示();
}

第三步,编写具体装饰角色(钛合金装甲等模块)

钛合金装甲模块

package 设计模式.结构型模式.装饰器模式;

public class 钛合金装甲模块 extends 外设类 {

    public 钛合金装甲模块(机甲类 待装机甲) {
        super(待装机甲);
    }

    @Override
    public void 展示() {
        // 执行装饰类附加的功能
        System.out.println("装备【钛合金装甲模块】");
        // 最后执行被装饰类的功能
        待装机甲.展示();
    }
}

微型核能续航模块

package 设计模式.结构型模式.装饰器模式;

public class 微型核能续航模块 extends 外设类 {

    public 微型核能续航模块(机甲类 待装机甲) {
        super(待装机甲);
    }

    @Override
    public void 展示() {
        // 执行装饰类附加的功能
        System.out.println("装备【微型核能续航模块】");
        // 最后执行被装饰类的功能
        待装机甲.展示();
    }
}

自动追踪导弹模块

package 设计模式.结构型模式.装饰器模式;

public class 自动追踪导弹模块 extends 外设类 {

    public 自动追踪导弹模块(机甲类 待装机甲) {
        super(待装机甲);
    }

    @Override
    public void 展示() {
        // 执行装饰类附加的功能
        System.out.println("装备【自动追踪导弹模块】");
        // 最后执行被装饰类的功能
        待装机甲.展示();
    }
}

多功能组合臂模块

package 设计模式.结构型模式.装饰器模式;

public class 多功能组合臂模块 extends 外设类 {

    public 多功能组合臂模块(机甲类 待装机甲) {
        super(待装机甲);
    }

    @Override
    public void 展示() {
        // 执行装饰类附加的功能
        System.out.println("装备【多功能组合臂模块】");
        // 最后执行被装饰类的功能
        待装机甲.展示();
    }
}

重装弱重力推进器

package 设计模式.结构型模式.装饰器模式;

public class 重装弱重力推进器 extends 外设类 {

    public 重装弱重力推进器(机甲类 待装机甲) {
        super(待装机甲);
    }

    @Override
    public void 展示() {
        // 执行装饰类附加的功能
        System.out.println("装备【重装弱重力推进器】");
        // 最后执行被装饰类的功能
        待装机甲.展示();
    }
}


第四步,编写测试类测试

测试类

package 设计模式.结构型模式.装饰器模式;

public class 测试类 {
    public static void main(String[] args) {
        // 开始组装第一台机甲
        System.out.println("开始组装第一台机甲:爱国机甲");
        机甲类 爱国机甲 = new 机甲类();
        // 对爱国机甲进行装饰
        爱国机甲 = new 自动追踪导弹模块(爱国机甲);
        爱国机甲 = new 微型核能续航模块(爱国机甲);
        爱国机甲 = new 钛合金装甲模块(爱国机甲);
        // 展示爱国机甲
        爱国机甲.展示();

        System.out.println("——————————————————————————————————");
        // 组装第二台机甲,对被装饰类进行不同的装饰
        System.out.println("开始组装第二台机甲:友善机甲");
        机甲类 友善机甲 = new 机甲类();
        // 对友善机甲进行装饰
        友善机甲 = new 重装弱重力推进器(友善机甲);
        友善机甲 = new 钛合金装甲模块(友善机甲);
        友善机甲 = new 多功能组合臂模块(友善机甲);
        友善机甲 = new 微型核能续航模块(友善机甲);
        友善机甲 = new 自动追踪导弹模块(友善机甲);
        // 展示友善机甲
        友善机甲.展示();

    }
}

测试结果

开始组装第一台机甲:爱国机甲
装备【钛合金装甲模块】
装备【微型核能续航模块】
装备【自动追踪导弹模块】
机甲开始组装……组装完毕!
——————————————————————————————————
开始组装第二台机甲:友善机甲
装备【自动追踪导弹模块】
装备【微型核能续航模块】
装备【多功能组合臂模块】
装备【钛合金装甲模块】
装备【重装弱重力推进器】
机甲开始组装……组装完毕!

Process finished with exit code 0

image-20221125194326790




本文参考

《大话设置模式》 作者:程杰

菜鸟教程 装饰器模式

设计模式学习笔记(十)装饰器模式及其应用

24 设计模式——装饰器模式(装饰设计模式)详解

设计模式之装饰器模式详解

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

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

相关文章

一个年薪20万软件测试工程师都具备的能力,你有吗?

今天和大家一起来讨论一下一个很火的问题:作为软件测试工程师需要具备哪些实力。 硬实力:学历技术 目前随着社会的发展,各个行业对岗位学历的要求也越来越高,尤其是对于工资水平高的技术岗位。 测试通用技能: 软件…

Revit中参数化弹簧族怎么做?

Revit中参数化弹簧族制作 第一步:新建族,族样板选择 “公制常规模型第二步:在平面视图中,在中心参照平面两端创建两条参照平面,等分标注,赋予其参数“一圈弹簧直径”,如图 1 第三步:…

环糊精-PEG-麦芽糖 maltose-Cyclodextrin 麦芽糖-环糊精

环糊精-PEG-麦芽糖 maltose-Cyclodextrin 麦芽糖-环糊精 英文名称:maltose-Cyclodextrin 别称:环糊精修饰麦芽糖,环糊精-麦芽糖 还可以提供PEG接枝修饰麦芽糖,麦芽糖-聚乙二醇-环糊精Cyclodextrin-PEG-maltose,环糊…

05、Spring事务详解

本文主要介绍Spring中的事务相关知识: 1、熟悉事务管理的三个核心接口 2、了解Spring事务的两种方式 3、掌握基于XML和注解的事务使用 1、Spring事务管理概述 1、事务管理的核心接口 1、PlatformTransactionManager PlatformTransactionManage接口是Spring平台提…

FineReport智能表格软件-JS实现大数据集导出(一)

前言 帆软FineReport大批量数据导出的时候,会对服务器、网络传输、数据库造成一定的压力。为了防止这样的风险,FineReport 11.0 新增了「大数据集导出」的功能,可直接根据数据集结果进行导出。 1.接口简介与注意事项 1.1 接口简介 大数据…

Redis订阅发布

Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接受消息。(微信、微博、关注系统) Redis客户端可以订阅任意数量的频道 订阅发布消息图: 三个角色:消息发送者、频道、消息订…

VMware 安装Ubuntu22.04

0、前提条件 操作系统:Windows10 VMware Workstation版本:15.1.0 build-13591040 1、安装 下载地址:下载Ubuntu桌面系统 | Ubuntu 打开VMware,选择文件 -> 新建虚拟机 配置类型选择典型,单击“下一步”按钮 选择…

python操作Excel之提取字符串中的中文/过滤字符串(win32com)

Python实用篇-Excel1.前言2.关于Excel3.win32com库操作4.问题解决4.1.问题描述4.2.安装库4.3.编码与解决1.前言 本人大学期间自学了Python后,但是又因不是大数据相关专业,并且没有计划从事Python相关方向,之后就几乎没有怎么使用过Python了。…

智慧城市应用数据治理的作用有哪些?

智慧城市是基础设施发展的新热词。 主要是指在城市规划、设计、建设、管理与运营等领域中,通过物联网、云计算、大数据、空间地理信息集成等智能计算技术的应用,使得城市管理、教育、医疗、房地产、交通运输、公用事业和公众安全等城市组成的关键基础设施…

现代密码学导论-10-EAV安全

目录 3.2.1 安全的基本定义(EAV-安全) 不可区分实验 The adversarial indistinguishability experiment DEFINITION 3.8 EAV-安全的等价定义(一) DEFINITION 3.9 EAV-安全的等价定义(二) 证明EAV-安全…

[b01lers2020]Welcome to Earth

刚点进来会一直加载&#xff0c;然后跳转到了/die 看一下刚进来页面的源代码 <!DOCTYPE html> <html><head><title>Welcome to Earth</title></head><body><h1>AMBUSH!</h1><p>Youve gotta escape!</p>&l…

leetcode:1157. 子数组中占绝大多数的元素【暴力遍历 + 随机算法相信概率】

目录题目截图题目分析暴力二分随机二分总结题目截图 题目分析 一个很暴力的思路就是把每个num出现的idx记录起来&#xff0c;然后按出现的频率排序优化每次query&#xff0c;遍历每个元素和频率&#xff0c;频率如果已经比threhold小就没有看的必要&#xff0c;直接break如果比…

虎扑论坛数据分析

论坛为用户提供了相同的业余爱好&#xff0c;互动和交流的广阔平台&#xff0c;以及由此产生的庞大数据和复杂的用户交互场景也包含有价值的信息&#xff0c;本文关于虎扑论坛的帖子&#xff0c;个人信息分析&#xff0c;探讨虎扑论坛的用户是什么是什么特点&#xff1f;最近我…

Spring Cloud Stream绑定器架构解析与开发

Spring Cloud Stream绑定器架构解析与开发 根据不同的使用场景我们通常会选择相适应的消息中间件&#xff0c;例如对于日志收集场景可能会选择使用Kafka&#xff0c;对于订单场景通常会选择RocketMQ&#xff0c;不同消息中间件的客户端是不同的&#xff0c;我们需要针对不同消息…

智慧城市面临的机遇与挑战

区域中心城市建设需要智慧城市支撑 建设区域中心城市&#xff0c;除了需要具备在公路、铁路、航空等区域中心城市的枢纽硬件设施外&#xff0c;更需要充分发挥信息化强有力的凝聚和辐射作用&#xff0c;提升区域中心城市在区域交通枢纽服务、区域金融商贸服务、区域物流集散服务…

百趣代谢组学文献分享:茶褐素可促进胆固醇降解

​ 为了解决大家每逢过节必长胖的历史性问题&#xff0c;小编今天给大家介绍一篇发表于Nature Communications 的针对于普洱茶促进减肥的研究。 百趣代谢组学文献分享&#xff0c;所谓药食同源&#xff0c;普洱茶是我国西南云南地区特有的一种传统名茶&#xff0c;因其具有治…

[激光原理与应用-18]:《激光原理与技术》-4- 粒子数反转与“光”强放大的基本原理

目录 一、热平衡&#xff1a; 受激辐射 < 受激接收 二、 “光”相干放大 三、粒子数反转&#xff08;population inversion&#xff09; 四、实现粒子数反转的装置&#xff1a;泵浦 五、实现粒子数反转的条件 六、实现粒子数反转的工作物质 七、实现粒子数反转的方式…

【菜菜的sklearn课堂笔记】逻辑回归与评分卡-用逻辑回归制作评分卡-重复值和缺失值处理

视频作者&#xff1a;菜菜TsaiTsai 链接&#xff1a;【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili 在银行借贷场景中&#xff0c;评分卡是一种以分数形式来衡量一个客户的信用风险大小的手段&#xff0c;它衡量向别人借钱的人&#xff08;受信人&…

「Vue系列」欢迎传送到“Teleport”星球

前言 大家好&#xff0c;我是落叶小小少年&#xff0c;我一直谨记学习不断&#xff0c;分享不停&#xff0c;输入的最好方式是输出&#xff0c;我始终相信 用最核心代码更容易理解深的技术点用通俗易懂的话&#xff0c;讲难的知识点 之前有学习并写了KeepAlive组件的实现原理…

Nginx 报错问题汇总(持续更新ing)

目录 一、nginx: [emerg] invalid number of arguments in "include" directive in C:\Program Files\nginx-1.15.4/conf/nginx.conf:61 总结&#xff1a; 二、nginx: [error] OpenEvent("Global\ngx_reload_2152") failed (5: Access is denied) 解决方…