Java特性之设计模式【装饰器模式】

一、装饰器模式

概述

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装

装饰器模式通过将对象包装在装饰器类中,以便动态地修改其行为

主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀

何时使用:在不想增加很多子类的情况下扩展类

优缺点

优点:

  • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能

缺点:

  • 多层装饰比较复杂

1. 各个角色介绍

1.1 抽象组件(Component)

  • 定义了组合中所有对象的通用接口,可以是抽象类或接口。它声明了用于访问和管理子组件的方法,包括添加、删除、获取子组件等

1.2 具体组件(Concrete Component)

  • 是被装饰的原始对象,它定义了需要添加新功能的对象

1.3 抽象装饰器(Decorator)

  • 继承自抽象组件,它包含了一个抽象组件对象,并定义了与抽象组件相同的接口,同时可以通过组合方式持有其他装饰器对象

1.4 具体装饰器(Concrete Decorator)

  • 实现了抽象装饰器的接口,负责向抽象组件添加新的功能。具体装饰器通常会在调用原始对象的方法之前或之后执行自己的操作

2. UML图

​ 将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。RedShapeDecorator 是实现了 ShapeDecorator 的实体类

在这里插入图片描述

3. 具体例子和代码

角色分配

  • Shape:形状接口

    • Rectangle:实现形状接口的长方形类
    • Circle:实现形状接口的圆形类
  • ShapeDecorator:形状装饰器抽象类

    • RedShapeDecorator:红色形状装饰器(继承ShapeDecorator)

3.1 抽象组件及其实现类

  • Shape
package com.vinjcent.prototype.decorator;

/**
 * @author vinjcent
 * @description 形状接口
 * @since 2024/3/15 16:23
 */
public interface Shape {

    /**
     * 形状绘制动作
     */
    void draw();

}

  • Rectangle
package com.vinjcent.prototype.decorator;

/**
 * @author vinjcent
 * @description 长方形
 * @since 2024/3/15 16:26
 */
public class Rectangle implements Shape {

    @Override
    public void draw() {
        System.out.println("Shape: Rectangle");
    }

}

  • Circle
package com.vinjcent.prototype.decorator;

/**
 * @author vinjcent
 * @description 圆形
 * @since 2024/3/15 16:28
 */
public class Circle implements Shape {

    @Override
    public void draw() {
        System.out.println("Shape: Circle");
    }

}

3.2 抽象装饰器及其具体装饰器

  • ShapeDecorator
package com.vinjcent.prototype.decorator;

/**
 * @author vinjcent
 * @description 形状装饰器
 * @since 2024/3/15 16:30
 */
public abstract class ShapeDecorator implements Shape {

    protected Shape decoratedShape;

    public ShapeDecorator(Shape decoratedShape) {
        this.decoratedShape = decoratedShape;
    }

    public void draw() {
        decoratedShape.draw();
    }

}

  • RedShapeDecorator
package com.vinjcent.prototype.decorator;

/**
 * @author vinjcent
 * @description 红色形状装饰器
 * @since 2024/3/15 16:32
 */
public class RedShapeDecorator extends ShapeDecorator {

    public RedShapeDecorator(Shape decoratedShape) {
        super(decoratedShape);
    }

    @Override
    public void draw() {
        decoratedShape.draw();
        setRedBorder(decoratedShape);
    }

    private void setRedBorder(Shape decoratedShape) {
        System.out.println("Border Color: Red");
    }

}

3.3 测试主函数

package com.vinjcent.prototype.decorator;

/**
 * @author vinjcent
 * @description 装饰器模式
 * @since 2024/3/15 16:39
 */
public class Main {

    public static void main(String[] args) {

        Shape circle = new Circle();
        // ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
        // ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
        Shape redCircle = new RedShapeDecorator(new Circle());
        Shape redRectangle = new RedShapeDecorator(new Rectangle());
        System.out.println("Circle with normal border");
        circle.draw();

        System.out.println("\nCircle of red border");
        redCircle.draw();

        System.out.println("\nRectangle of red border");
        redRectangle.draw();
    }

}

  • 测试结果

在这里插入图片描述

4. 使用场景

  • 动态增强功能:使用装饰器模式可在运行时为对象灵活地增加额外功能。通过组合各种装饰器,能够实现不同功能的组合,而无需改变原始对象的代码
  • 避免继承的功能扩展:当使用继承来增强对象功能时会导致类的层次结构过于复杂时,考虑采用装饰器模式。通过组合而非继承来实现功能扩展,避免了深层次和复杂的类继承结构
  • 维护对象的封装性:若需为对象添加功能,同时又不愿修改原始对象的代码或破坏其封装性,可采用装饰器模式。该模式不改变原对象结构,只是在其上方增添功能
  • 弹性组合多项功能:若需为对象添加多项功能,且这些功能可弹性组合,则可采用装饰器模式。透过组合各种装饰器,能够实现各种功能的组合,而无需创建大量子类
  • 贯彻单一职责原则:在需要将功能添加与原始对象实现分离,以符合单一职责原则时,可采用装饰器模式。每个装饰器类专注于一个特定功能,这有助于使类的职责更加明确

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

单片机--数电(4)

触发器 数字电路中:分组合逻辑电路与时序逻辑电路两大类 组合逻辑电路的基本单元是门电路(与或非等一些门电路) 时序逻辑电路的基本单元是触发器 触发器与门电路的区别 门电路某一时刻的输出信号完全取决于该时刻的输入信号,…

【目标检测实验系列】AutoDL线上GPU服务器租用流程以及如何用Pycharm软件远程连接服务器进行模型训练 (以Pycharm远程训练Yolov5项目为例子 超详细)

目录 1. 文章主要内容2. 租用AutoDL服务器详细教程2.1 注册AutoDL账号,并申请学生认证(学生认证有优惠,如果不是学生可以忽略此点)2.2 算力市场选择GPU,并选择初始化配置环境2.3 控制台参数解析,并使用相关参数登录Xftp(Windows与…

安卓开发日记:实现APP重启逻辑,适用于热更后重启游戏进行加载

可根据合适的弹窗搭配使用重启逻辑,建议使用在热更包加载后使用,帮助部分热更后未及时生效的逻辑范围首先,在逻辑调用Activity类中创建一个成员变量,给后续逻辑接口直接使用 如下 public class MainActivity extends Activity {…

rundeck k8s部署踩坑

1、镜像启动后原来的定时任务无法运行 参考: https://github.com/rundeck/rundeck/issues/4275 https://stackoverflow.com/questions/60942785/env-variable-for-rundeck-feature-joblifecycleplugin-enabled/60959605#60959605 结论: (1&…

vue3项目中使用 hiprint

基于 vue3 的打印 hiprint 打印官网 hiprint hiprint 是一个web 打印的js组件,无需安装软件。支持移动端,PC端浏览器,angular,vue,react, 等 分页预览,打印,操作简单,运行快速。 在 vue3 项目中使用打印&a…

【嵌入式学习】Qtday03.21

一、思维导图 二、练习 自由发挥登录窗口的应用场景,实现一个登录窗口界面。(不要使用课堂上的图片和代码,自己发挥,有利于后面项目的完成) 要求: 1. 需要使用Ui界面文件进行界面设计 2. ui界面上的组件…

shell脚本命令

最后更新日期:2024-03-21 文章目录 一、echo二、特殊变量1、$n2、$#3、$*4、$5、$? 三、运算符1、expr2、$[nn] 三、条件判断1、[ condition ]2、&&3、|| 四、流程控制1、if2、case3、for4、while 五、read读取控制台输入 一、echo 打印变量 #! /bin/ba…

k8s安装详细教程1

环境初始化 1、检查操作系统的版本 Last login: Mon Mar 18 08:57:10 2024 [rootcontroller ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootcontroller ~]# vi /etc/hosts2、时间同步 kubernetes要求集群中的节点时间必须精确一直,这里…

32.网络游戏逆向分析与漏洞攻防-游戏网络通信数据解析-网络数据分析原理与依据

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 如果看不懂、不知道现在做的什么,那就跟着做完看效果 内容参考于:易道云信息技术研究院VIP课 上一个内容:31.其它消息的实…

除了Confluence,有没有其他工具一样好用?

每个团队都需要一个协同工作工具,以更有效地管理任务、跟踪进度和分享知识。这就是Atlassian的Confluence发挥作用的地方。然而,尽管它相当强大,其昂贵的价格和复杂的界面可能会让某些用户望而却步。所以,还有其他工具可以替代Con…

Markdown快速入门(常用技巧)

目录 说明常用书写技巧1.标题分级2.代码块3.字体4.引用语法5.分割线6.图片插入(本地/网络)7.超链接8.列表9.表格10.换行(两个空格)11.插入公式12.脚注 说明 markdown实际上类似于网页,可以根据喜欢设置其样式变化,创建…

多模态开源大模型

感知类总榜单,是将各项感知任务综合起来的总评分,显示是BLIP-2最高: 认知类总榜单,则是各种涉及认知类任务的榜单,加起来是MiniGPT-4最高: 一、LLaVA-1.5(浙大实验室》:LLaVA 二、…

如何修复WordPress网站媒体库上传文件失败的问题

公司最近推出了一系列新产品,为了更新网站的视频和图片,我们需要将它们上传至网站媒体库。然而,在上传视频时,我们却遇到了一些问题。系统提示说,我们尝试上传的视频文件大小超出了站点的最大上传限制。尽管我们的视频…

实战whisper第二天:直播语音转字幕(全部代码和详细部署步骤)

直播语音实时转字幕: 基于Whisper的实时直播语音转录或翻译是一项使用OpenAI的Whisper模型实现的技术,它能够实时将直播中的语音内容转录成文本,甚至翻译成另一种语言。这一过程大致分为三个步骤:捕获直播音频流、语音识别&#x…

【嵌入式——QT】QT Charts

【嵌入式——QT】QT Charts 概述Qt提供的坐标轴类QChartQLineSeriesQValueAxis常见图表及用到的序列类图示代码示例 概述 QT Charts模块是一组易于使用的图表组件,它基于Qt的Graphics View架构,其核心组件是QChartView和QChart,QChartView父…

前端开发经验分享:写页面时总是有预期之外的滚动条怎么办?

问题描述: 在制作一个页面时常常会出现一些预期之外的滚动条,一般有以下原因:1.内容过多:当容器内的内容(如文本、图片等)的总高度或总宽度超过容器的可视区域时,滚动条就会出现。2.样式设置&a…

一维前缀和一维差分(下篇讲解二维前缀和二维差分)(超详细,python版,其他语言也很轻松能看懂)

本篇博客讲解一维前缀和,一维差分,还会给出一维差分的模板题,下篇博客讲解 二维前缀和&二维差分。 一维前缀和: 接触过算法的小伙伴应该都了解前缀和,前缀和在算法中应用很广,不了解也没有关系&#…

基于SSM的中国旅游网站管理系统+数据库+数据库表结构文档+免费远程调试

项目介绍: Javaee项目,采用M(model)V(view)C(controller)三层体系结构,通过Spring SpringMvc Mybatis JspBootstrap来实现。MySQL数据库作为系统数据储存平台&#xff…

阻止默认行为 e.preventDefault()搭配passive:false才有效

正确情况 如果想阻止默认行为,那么 e.preventDefault()搭配passive:false才是正解 document.addEventListener(touchmove,(e)>{ e.preventDefault() console.log(123,123);},{passive:false}) 如果搭配 passive:false,则会报警告 e.preventDefault()搭配passive:true会报…

php 对接Vungle海外广告平台收益接口Reporting API

今天对接的是Vungle广告reporting api接口,拉取广告收益回来自己做统计。记录分享给大家 首先是文档地址,进入到Vungle后台就能看到文档地址以及参数: 文档地址:https://support.vungle.com/hc/en-us/articles/211365828-Publisher-Reporting…