设计模式——装饰器模式(Decorator Pattern)+ Spring相关源码
文章目录
- 一、装饰器模式的定义
- 二、个人理解
- 举个抽象的例(可能并不是很贴切)
- 三、例子
- 1、菜鸟教程例子
- 1.1、定义对象
- 1.2、定义装饰器
- 3、JDK源码 ——包装类
- 4、JDK源码 —— IO、OutputStreamWriter
- 5、Spring源码 —— BeanWrapperImpl
- 5、SpringMVC源码 —— HttpHeadResponseDecorator
- 四、其他设计模式
一、装饰器模式的定义
- 别名:包装模式(Wrapper Pattern)
- 类型:结构型模式。
- 目的:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责额外功能。
二、个人理解
给对象添加新功能时,并不是在对象类中直接添加,而是在装饰器类中添加。
在装饰类中添加新功能,你可以增强原先对象的方法,也可以给对象新增一个方法。
举个抽象的例(可能并不是很贴切)
假设要给人类添加开炮功能。
但由于这是人类,咱们不能通过继承直接给人类添加开炮功能;
所以我们就得通过组合,将机器和人类组合起来、通过变相实现人类可以开炮。
这个机器就是装饰器。
- 坦克 + 人类 ,实现开炮功能
- 高达 + 人类 ,实现开炮功能
三、例子
1、菜鸟教程例子
菜鸟教程的例子都将对象和装饰器进行了抽象处理,实现了可替换对象和装饰器的实现类。
菜鸟教程原例子
个人觉得这样理解装饰器太绕了,下面的例子就只保留了对象和装饰器。
1.1、定义对象
定义一个圆的对象
public class Circle{@Overridepublic void draw() {System.out.println("Shape: Circle");}
}
1.2、定义装饰器
新增setRedBorder方法去设置红色边框。
public class RedCircleDecorator{private Circle c;public RedCircleDecorator(Circle c) {this.c = c;}@Overridepublic void draw() {decoratedShape.draw(); setRedBorder(decoratedShape);}private void setRedBorder(Circle decoratedShape){System.out.println("Border Color: Red");}
}
但我觉这个菜鸟这个例子并不能把装饰器模式特点表现出来。
因setRedBorder是私有,并且只是把原先draw方法进行了增强。
这样的话,代理模式也能实现,代理模式也能增强原有的方法,所以这里并不能把装饰器模式特点表现出来。
所以我改了一下。
public class ColorCircleDecorator{private Circle c;public RedCircleDecorator(Circle c) {this.c = c;}@Overridepublic void draw() {decoratedShape.draw();System.out.println("画了个普通的圆"); }public void drawRedCircle(Circle decoratedShape){decoratedShape.draw();System.out.println("画了个红色的圆");}public void drawBlueCircle(Circle decoratedShape){decoratedShape.draw();System.out.println("画了个蓝色的圆");}
}
这个例子保留了原先的draw功能,又新增了drawRedCircle和drawBlueCircle功能。
3、JDK源码 ——包装类
包装类也运用了装饰器模式。
将基本类型 转 包装类 的同时,还提供各种转换类型的功能。
4、JDK源码 —— IO、OutputStreamWriter
OutputStreamWriter同时运用了装饰器模式+适配器模式。
这里我们拿装饰器部分来讲。
FileOutputStream fos = new FileOutputStream(new File("Y:/学习资料.md"));
OutputStreamWriter osw = new OutputStreamWriter(fos);
osw.append("新资料xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
原本FileOutputStream 是原本没有append功能的,
而在中OutputStreamWriter 添加append功能。
源码:
public class OutputStreamWriter extends Writer {private final StreamEncoder se;public OutputStreamWriter(OutputStream out) {super(out);se = StreamEncoder.forOutputStreamWriter(out, lockFor(this),out instanceof PrintStream ps ? ps.charset() : Charset.defaultCharset());}@Overridepublic Writer append(CharSequence csq) throws IOException {if (csq instanceof CharBuffer) {se.write((CharBuffer) csq);} else {se.write(String.valueOf(csq));}return this;}
}
可以看到虽然OutputStreamWriter 重写了append方法。
但构造器里OutputStream又被新的装饰器StreamEncoder接收。
而StreamEncoder类就已经通过继承Writer 增加了append方法。
public final class StreamEncoder extends Writer {private final OutputStream out;private StreamEncoder(OutputStream out, Object lock, CharsetEncoder enc) {super(lock);this.out = out;this.ch = null;this.cs = enc.charset();this.encoder = enc;this.bb = ByteBuffer.allocate(INITIAL_BYTE_BUFFER_CAPACITY);this.maxBufferCapacity = MAX_BYTE_BUFFER_CAPACITY;}public static StreamEncoder forOutputStreamWriter(OutputStream out, Object lock, Charset cs) {return new StreamEncoder(out, lock, cs);}
}
5、Spring源码 —— BeanWrapperImpl
BeanWrapperImpl类是对BeanWrapper接口的默认实现,它包装了一个bean对象,缓存了bean的内省结果,并可以访问bean的属性、设置bean的属性值。
BeanWrapperImpl功能还挺复杂的,大家可以自行去看源码,我就不贴出来了。
5、SpringMVC源码 —— HttpHeadResponseDecorator
HttpHeadResponseDecorator 给ServerHttpResponse 添加了writeWith、writeAndFlushWith的功能。
public class HttpHeadResponseDecorator extends ServerHttpResponseDecorator {public HttpHeadResponseDecorator(ServerHttpResponse delegate) {super(delegate);}public final Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {return this.shouldSetContentLength() && body instanceof Mono ? ((Mono)body).doOnSuccess((buffer) -> {if (buffer != null) {this.getHeaders().setContentLength((long)buffer.readableByteCount());DataBufferUtils.release(buffer);} else {this.getHeaders().setContentLength(0L);}}).then() : Flux.from(body).doOnNext(DataBufferUtils::release).then();}private boolean shouldSetContentLength() {return this.getHeaders().getFirst("Content-Length") == null && this.getHeaders().getFirst("Transfer-Encoding") == null;}public final Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {return this.setComplete();}
}
四、其他设计模式
创建型模式
结构型模式
- 1、设计模式——装饰器模式(Decorator Pattern)+ Spring相关源码
行为型模式
- 1、设计模式——访问者模式(Visitor Pattern)+ Spring相关源码
- 2、设计模式——中介者模式(Mediator Pattern)+ JDK相关源码
相关文章:
设计模式——装饰器模式(Decorator Pattern)+ Spring相关源码
文章目录 一、装饰器模式的定义二、个人理解举个抽象的例(可能并不是很贴切) 三、例子1、菜鸟教程例子1.1、定义对象1.2、定义装饰器 3、JDK源码 ——包装类4、JDK源码 —— IO、OutputStreamWriter5、Spring源码 —— BeanWrapperImpl5、SpringMVC源码 …...
MATLAB R2018b详细安装教程(附资源)
云盘链接: pan.baidu.com/s/1SsfNtlG96umfXdhaEOPT1g 提取码:1024 大小:11.77GB 安装环境:Win10/Win8/Win7 安装步骤: 1.鼠标右击【R2018b(64bit)】压缩包选择【解压到 R2018b(64bit)】 2.打开解压后的文件夹中的…...
GEE错误——影像加载过程中出现的图层无法展示的解决方案
问题: // I dont know if some standard value exists for the radius, in the same, I will assume that some software would prefer to use square shape, but circle makes more sense to me. // pixels is noice if you want to zoom in and out to visualize…...
读图数据库实战笔记03_遍历
1. Gremlin Server只将数据存储在内存中 1.1. 如果停止Gremlin Server,将丢失数据库里的所有数据 2. 概念 2.1. 遍历(动词) 2.1.1. 当在图数据库中导航时,从顶点到边或从边到顶点的移动过程 2.1.2. 类似于在关系数据库中的查…...
QT如何检测当前系统是是Windows还是Uninx或Mac?以及是哪个版本?
简介 通过Qt获取当前系统及版本号,需要用到QSysInfo。 QSysInfo类提供有关系统的信息。 WordSize指定了应用程序编译所在的平台的指针大小。 ByteOrder指定了平台是大端序还是小端序。 某些常量仅在特定的平台上定义。您可以使用预处理器符号Q_OS_WIN和Q_OS_MACOS来…...
Maven配置阿里云中央仓库settings.xml
Maven配置阿里云settings.xml 前言一、阿里云settings.xml二、使用步骤1.任意目录创建settings.xml2.使用阿里云仓库 总结 前言 国内网络从maven中央仓库下载文件通常是比较慢的,所以建议配置阿里云代理镜像以提高jar包下载速度,IDEA中我们需要配置自己…...
由浅入深C系列八:如何高效使用和处理Json格式的数据
如何高效使用和处理JSON格式的数据 问题引入关于CJSON示例代码头文件引用处理数据 问题引入 最近的项目在用c处理后台的数据时,因为好多外部接口都在使用Json格式作为返回的数据结构和数据描述,如何在c中高效使用和处理Json格式的数据就成为了必须要解决…...
多媒体应用设计师 第16章 多媒体应用系统的设计和实现示例
口诀 思维导图 2020...
golang平滑重启库overseer实现原理
overseer主要完成了三部分功能: 1、连接的无损关闭,2、连接的平滑重启,3、文件变更的自动重启。 下面依次讲一下: 一、连接的无损关闭 golang官方的net包是不支持连接的无损关闭的,当主监听协程退出时,…...
用Python定义一个函数,用递归的方式模拟汉诺塔问题
【任务需求】 定义一个函数,用递归的方式模拟汉诺塔问题,三个柱子,分别为A、B、C,其中A柱子上有N个盘子,从小到大编号为1到N,盘子大小不同。现在要将这N个盘子从A柱子移动到C柱子上,但移动的过…...
二手的需求
案例1030 某天项目经理小王,从用户现场带回了需求,以图形的方式,交给了产品经理。告诉他就照这样设计,结果是项目经理放弃让产品经理出效果图。 原因是产品经理觉得项目经理带回来的需求有问题。项目经理解释产品经理不接受&…...
大厂面试题-JVM为什么使用元空间替换了永久代?
目录 面试解析 问题答案 面试解析 我们都知道Java8以及以后的版本中,JVM运行时数据区的结构都在慢慢调整和优化。但实际上这些变化,对于业务开发的小伙伴来说,没有任何影响。 因此我可以说,99%的人都回答不出这个问题。 但是…...
基本微信小程序的驾校宝典系统-驾照考试系统
项目介绍 系统模块分析是对系统的各个模块做出相应的说明以及解释。此系统的模块分别有用户模块、服务端模块和管理端模块这两大基本模块,其中服务端模块包括了首页、教练信息、教练咨讯、考试预约、我的等;而管理端模块则包括了个人中心、用户管理、教…...
02、SpringCloud -- Redis和Cookie过期时间刷新功能
目录 需求:代码流程过滤器类工具类过滤判断远程调用feign接口gitee 配置接口实现过滤器run方法测试:问题:秒杀功能完整分析图 需求: cookie应该写在网关中,网关中可以自定义filter过滤器,用来实现cookie的刷新和redis中key的刷新,延长用户的操作时间。 就是让用户每操…...
【报错】kali安装ngrok报错解决办法(zsh: exec format error: ./ngrok)
问题描述 kali安装ngrok令牌授权失败 在安装配置文件的时候报错:zsh: exec format error: ./ngrok 原因分析: 在Kali Linux上执行./ngrok时出现zsh exec格式错误的问题可能是由于未安装正确版本的ngrok或操作系统不兼容ngrok导致的。以下是一些可能的解…...
<学习笔记>从零开始自学Python-之-常用库篇(十三)内置小型数据库shelve
一、shelve简介: shelve是Python当中数据储存的方案,类似key-value数据库,便于保存Python对象,shelve只有一个open()函数,用来打开指定的文件(字典),会返回一…...
Redis快速上手篇七(集群-六台虚拟机)
Redis集群 主从复制的场景无法吗满足主机单点故障时需要引入集群配置 一般数据库要处理的读请求远大于写请求 ,针对这种情况,我们优化数据库可以采用读写分离的策略。我们可以部 署一台主服务器主要用来处理写请求,部署多台从服务器 &#…...
LeetCode 301. 删除无效的括号【字符串,回溯或BFS】困难
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...
面试经典159题——Day25
文章目录 一、题目二、题解 一、题目 125. Valid Palindrome A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric charact…...
C# OpenCvSharp DNN 部署L2CS-Net人脸朝向估计
效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Dnn; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Windows.Forms;namespace OpenCvSharp_DNN_Demo …...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...
解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC…...
HTTPS证书一年多少钱?
HTTPS证书作为保障网站数据传输安全的重要工具,成为众多网站运营者的必备选择。然而,面对市场上种类繁多的HTTPS证书,其一年费用究竟是多少,又受哪些因素影响呢? 首先,HTTPS证书通常在PinTrust这样的专业平…...
深入解析光敏传感技术:嵌入式仿真平台如何重塑电子工程教学
一、光敏传感技术的物理本质与系统级实现挑战 光敏电阻作为经典的光电传感器件,其工作原理根植于半导体材料的光电导效应。当入射光子能量超过材料带隙宽度时,价带电子受激发跃迁至导带,形成电子-空穴对,导致材料电导率显著提升。…...
