设计模式-装饰器模式(Decorator)
设计模式-装饰器模式(Decorator)
- 一、装饰器模式概述
- 1.1 什么是装饰器模式
- 1.2 简单实现装饰器模式
- 1.3 使用装饰器模式的注意事项
- 二、装饰器模式的用途
- 三、装饰器模式的实现方式
- 3.1 通过接口和抽象类实现
- 3.2 通过Java反射实现
- 3.3 通过使用第三方库实现
一、装饰器模式概述
1.1 什么是装饰器模式
装饰器模式是一种结构型设计模式,它允许在运行时扩展一个对象的功能,而不需要改变其现有结构。这种模式的核心思想是通过创建一个包装类(装饰器)来动态地增强或修改原有对象的行为。
具体来说,装饰器模式的主要特点如下:
- 1、不改变原有对象的结构和方法。
- 2、通过创建一个与被装饰对象接口相同的装饰器类,实现对被装饰对象的包装。
- 3、可以在不改变现有代码的基础上,动态地给一个对象增加新的功能。
- 4、装饰器模式是继承的一个补充,提供了比继承更加灵活的方式来扩展对象的行为。
尽管装饰器模式非常灵活且可扩展,适用于需要动态地为对象增加功能的场景,但过度使用这种模式可能会导致系统的复杂性增加。因此,在使用装饰器模式时,需要确保真正需要扩展的地方使用,而不是滥用。
1.2 简单实现装饰器模式
装饰器模式是一种结构型设计模式,它允许在运行时动态地扩展一个对象的功能,而不需要改变其现有结构。下面是一个简单的 Java 实现装饰器模式的示例:
首先,我们创建一个接口 Component:
public interface Component {void operation();
}
然后,我们创建一个具体的组件类 ConcreteComponent:
public class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("具体组件的操作");}
}
接下来,我们创建一个抽象装饰器类 Decorator,它也实现了 Component 接口,并持有一个 Component 类型的对象:
public abstract class Decorator implements Component {protected Component component;public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {component.operation();}
}
现在,我们可以创建具体的装饰器类,例如 ConcreteDecoratorA 和 ConcreteDecoratorB,它们分别在原有功能的基础上添加新的功能:
public class ConcreteDecoratorA extends Decorator {public ConcreteDecoratorA(Component component) {super(component);}@Overridepublic void operation() {System.out.println("装饰器 A 的操作");super.operation();}
}public class ConcreteDecoratorB extends Decorator {public ConcreteDecoratorB(Component component) {super(component);}@Overridepublic void operation() {System.out.println("装饰器 B 的操作");super.operation();}
}
最后,我们在客户端代码中使用装饰器模式:
public class Client {public static void main(String[] args) {Component component = new ConcreteComponent();Component decoratorA = new ConcreteDecoratorA(component);Component decoratorB = new ConcreteDecoratorB(decoratorA);decoratorB.operation();}
}
运行客户端代码,输出结果如下:
装饰器 B 的操作
装饰器 A 的操作
具体组件的操作
1.3 使用装饰器模式的注意事项
- 1、装饰器模式适用于需要动态地为对象增加功能的场景,如果不需要动态扩展功能,则不必要使用装饰器模式。
- 2、装饰器模式会增加系统的复杂性,因此应该谨慎使用,避免过度使用。
- 3、装饰器模式要求被装饰的对象和装饰器类都必须实现相同的接口或继承相同的抽象类,否则无法进行装饰。
- 4、装饰器模式可能会导致设计上的冗余,因为每个装饰器都需要持有一个被装饰对象的引用,这会导致系统中存在大量的引用关系。
- 5、如果需要对多个对象进行同样的装饰操作,可以考虑使用代理模式或者享元模式来优化系统结构。
二、装饰器模式的用途
装饰器模式是一种结构型设计模式,它允许在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)。这种模式的核心在于创建一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
以下是装饰器模式的一些主要用途:
- 1、动态地为一个对象添加新的功能,同时又不改变其结构。这可以帮助我们在不修改原有组件、接口或者类的情况下为其添加额外的功能。
- 2、用于元类的使用情况,可以作为元类的一些简单替代方案。
- 3、在Java AWT和Swing中广泛使用,如为按钮、文本框等组件添加新的功能。
- 4、适用于Java I/O流,如BufferedReader、BufferedWriter等。通过装饰器模式,可以在不改变原有I/O流的基础上,为其增加新的功能。
- 5、在Python中也有广泛应用,如GIL(Global Interpreter Lock)就是一个典型的装饰器模式的实现。
三、装饰器模式的实现方式
3.1 通过接口和抽象类实现
通过定义一个接口或抽象类,然后创建具体的装饰器类来实现装饰器模式。这种方式适用于需要动态添加功能的场景。
// 定义一个接口
public interface Component {void operation();
}// 定义一个具体组件
public class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("具体组件的操作");}
}// 定义一个抽象装饰器类
public abstract class Decorator implements Component {protected Component component;public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {component.operation();}
}// 定义一个具体装饰器类
public class ConcreteDecorator extends Decorator {public ConcreteDecorator(Component component) {super(component);}@Overridepublic void operation() {super.operation();addedFunction();}public void addedFunction() {System.out.println("新增的功能");}
}// 客户端代码
public class Client {public static void main(String[] args) {Component component = new ConcreteComponent();Component decorator = new ConcreteDecorator(component);decorator.operation();}
}
3.2 通过Java反射实现
通过Java反射机制,可以在运行时动态地为对象添加新的功能。这种方式适用于需要根据条件动态改变行为的场景。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class DecoratorDemo {public static void main(String[] args) {MyInterface myInterface = (MyInterface) Proxy.newProxyInstance(MyInterface.class.getClassLoader(),new Class[]{MyInterface.class},new DecoratorInvocationHandler(new MyInterfaceImpl()));myInterface.doSomething();}
}interface MyInterface {void doSomething();
}class MyInterfaceImpl implements MyInterface {@Overridepublic void doSomething() {System.out.println("原始方法");}
}class DecoratorInvocationHandler implements InvocationHandler {private Object target;public DecoratorInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("装饰器开始执行");Object result = method.invoke(target, args);System.out.println("装饰器结束执行");return result;}
}
3.3 通过使用第三方库实现
有一些第三方库提供了装饰器模式的实现,如Spring框架中的AOP(面向切面编程)模块。这些库通常提供了更加完善的功能和更好的性能。
相关文章:
设计模式-装饰器模式(Decorator)
设计模式-装饰器模式(Decorator) 一、装饰器模式概述1.1 什么是装饰器模式1.2 简单实现装饰器模式1.3 使用装饰器模式的注意事项 二、装饰器模式的用途三、装饰器模式的实现方式3.1 通过接口和抽象类实现3.2 通过Java反射实现3.3 通过使用第三方库实现 一…...

Java 数据结构篇-实现双链表的核心API
🔥博客主页: 小扳_-CSDN博客 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 双链表的说明 1.1 双链表 - 创建 1.2 双链表 - 根据索引查找节点 1.3 双链表 - 根据索引插入节点 1.4 双链表 - 头插节点 1.5 双链表 - 尾插 1.6 双链表 - 根据索引来…...

电脑如何截屏?一起来揭晓答案!
在数字时代,截屏已经成为我们日常生活和工作中的必备技能。无论是为了捕捉有趣的网络瞬间,保存重要信息,还是为了协作和教育,电脑截屏都是一个强大而方便的工具。本文将介绍三种电脑如何截屏的方法,以满足各种需求&…...
【实战-08】flink 消费kafka自定义序列化
目的 让从kafka消费出来的数据,直接就转换成我们的对象 mvn pom <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information …...
深入浅出 Django 异步编程
随着 Web 应用对性能的要求日益提高,异步编程成为了提升响应速度、提高系统吞吐量的重要手段。Django 作为一个成熟的 Python Web 框架,自 3.1 版本开始支持了异步编程。在本文中,我们将探讨 Django 异步编程的关键概念,并提供实际…...
力扣 138. 随机链表的复制
文章目录 1.解题思路2.代码实现 1.解题思路 在原先链表的每一个元素后面插入一个与前一个相同val的值的结点,然后由于是在原链表进行的操作,因此找每个random就变得很方便直接访问即可,此题目的精髓是cur1->randomp->random->next,看懂这串代码…...

STM32外部中断大问题
问题:一直进入中断,没有触发信号,也一直进入。 描述:开PA0为外部中断,刚刚很好,一个触发信号一个中断,中断函数没有丢,也没有抢跑,开PA1为外部中断也是,都很好…...

FPGA配置采集AR0135工业相机,提供2套工程源码和技术支持
目录 1、前言免责声明 2、AR0135工业相机简介3、我这里已有的 FPGA 图像处理解决方案4、设计思路框架AR0135配置和采集图像缓存视频输出 5、vivado工程1–>Kintex7开发板工程6、vivado工程1–>Zynq7100开发板工程7、上板调试验证8、福利:工程代码的获取 1、前…...

KubeSphere v3.4.0 部署K8S Docker + Prometheus + grafana
KubeSphere v3.4.0 部署K8S 1、整体思路2、修改linux主机名3、 离线安装3.1 问题列表3.2 执行命令成功列表 1、整体思路 将KubeSphere v3.4.0 安装包传输到其中一台机器修改Linux主机名(选取3台,修改为master01、master02、master03)安装官方…...
Codeforces Round 908 (Div. 2)题解
目录 A. Secret Sport 题目分析: B. Two Out of Three 题目分析: C. Anonymous Informant 题目分析: A. Secret Sport 题目分析: A,B一共打n场比赛,输入一个字符串由A和‘B’组成代表A赢或者B赢(无平局),因为题目说明这个人…...

Redis笔记 Redis主从同步
文章目录 Redis主从搭建主从架构主从数据同步原理全量同步增量同步repl_backlog原理 主从同步优化小结 Redis主从 搭建主从架构 单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。 主从数据…...

数据结构-Prim算法构造无向图的最小生成树
引子: 无向图如果是一个网,那么它的所有的生成树中必有一颗生成树的边的权值之和是最小的,我们称 这颗权值和最小的树为:“最小生成树”(MST)。 其中,一棵树的代价就是树中所有权值之和。 而…...

MFC串口通信(SerialPort)
目录 1、SerialPort类的介绍和使用: (1)、SerialPort类的功能介绍 (2)、SerialPort类提供接口函数的介绍 1)、InitPort函数 2)、控制串口监视线程函数 3)、获取事件,…...

Vim基本使用操作
前言:作者也是初学Linux,可能总结的还不是很到位 Linux修炼功法:初阶功法 ♈️今日夜电波:美人鱼—林俊杰 0:21━━━━━━️💟──────── 4:14 …...

【深蓝学院】手写VIO第8章--相机与IMU时间戳同步--作业
0. 题目 1. T1 逆深度参数化时的特征匀速模型的重投影误差 参考常鑫助教的答案:思路是将i时刻的观测投到world系,再用j时刻pose和外参投到j时刻camera坐标系下,归一化得到预测的二维坐标(这里忽略了camera的内参,逆深…...
Naocs配置中心配置映射List、Map、Map嵌套List等方式
一、配置映射List 1、常规逐个配置方式,示例如下: 代码: @Data @Configuration @ConfigurationProperties(prefix = "list-json-str") public class ConfListByJsonStr implements Serializable, InitializingBean {@ApiModelProperty("映射结果集")…...

如何通过CRM系统进行销售机会管理?
销售机会管理是在销售过程中对潜在客户的精细化管理,销售机会管理的本质是公司用于管理销售机会通用的工具和方法。对于希望建立长期客户关系的现代销售团队来说,CRM客户管理系统是必不可少的工具。那企业如何通过CRM系统进行销售机会管理? …...

解决idea启动tomcat控制台中文乱码
#1.tomcat日志中文乱码# 如图这种情况,一般在idea用tomcat跑一个web项目启动后tomcat日志在控制台打印出来会出现中文乱码的情况 解决方案1:tomcat的日志配置文件的编码修改,找到tomcat安装目录conf下的logging.properties,encod…...
vscode + cmake + opencv example
nice try on macos CMakeLists.txt cmake_minimum_required(VERSION 3.20) #添加OPENCV库 #指定OpenCV版本,代码如下 #find_package(OpenCV 3.3 REQUIRED) #如果不需要指定OpenCV版本,代码如下 find_package(OpenCV REQUIRED)#添加OpenCV头文件 includ…...
day57【动态规划】647.回文子串 516.最长回文子序列
文章目录 647. 回文子串516.最长回文子序列 647. 回文子串 力扣题目链接 代码随想录讲解 题意:给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...

Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...