对装饰器模式的理解
目录
- 一、场景
- 二、面对场景中的新需求,我们怎么办?
- 1、暴力法:直接修改原有的代码。
- 2、子类继承法:既然要增强行为,那我搞一个子类,覆写不就完事了?
- 3、装饰器模式
- 三、对装饰器模式的思考
- 1、从代码结构上来看,咋和代理模式这么像呢?
- 2、设计原则 >> 设计模式
一、场景
- 在Java中,提供某种功能/服务给客户端(应用层的类)去使用,一般都是先定义接口,然后实现该接口。
// 应用层
@Component
public class DataSourceApplication {@Autowiredprivate DataSource dataSource;public void write(String data) {dataSource.writeData(data);}public String read() {return dataSource.readData();}
}
// 服务层
public interface DataSource {void writeData(String data);String readData();
}@Service
public class FileDataSourceImpl implements DataSource {@Overridepublic void writeData(String data) {System.out.println("[FileDataSourceImpl.writeData]");}@Overridepublic String readData() {System.out.println("[FileDataSourceImpl.readData]");return "FileDataSourceImpl.readData";}
}
- 这时候,产品经理要求写入数据前要先加密,读出数据后要解密。
二、面对场景中的新需求,我们怎么办?
1、暴力法:直接修改原有的代码。
@Service
public class FileDataSourceImpl implements DataSource {@Overridepublic void writeData(String data) {// 对数据加密...System.out.println("[FileDataSourceImpl.writeData]");}@Overridepublic String readData() {System.out.println("[FileDataSourceImpl.readData]");// 对数据进行解密...return "FileDataSourceImpl.readData";}
}
- 虽然这种做法存在一些问题,但在公司可能很普遍…(不然屎山怎么形成的?😃)
- 问题1:之前辛苦写的单测都白费了。(虽然并不是所有程序员都会写单测 😃)
- 问题2:逻辑耦合,数据的读写和数据的加密,从客观上来说,是相互独立的逻辑。
- 如果我们耦合在一起,那么方法会越来越冗长,逻辑也越来越不清晰。例如,产品经理又改需求了,要求支持多种加密算法。
2、子类继承法:既然要增强行为,那我搞一个子类,覆写不就完事了?
@Primary
@Service
public class EncryptFileDataSourceImpl extends FileDataSourceImpl {@Overridepublic void writeData(String data) {// 对数据进行加密String encryptedData = null;...super.writeData(encryptedData);System.out.println("[EncryptFileDataSourceImpl.writeData]");}@Overridepublic String readData() {super.readData();// 对数据进行解密...System.out.println("[EncryptFileDataSourceImpl.readData]");return "EncryptFileDataSourceImpl.readData";}
}
- 如果产品经理要求先压缩数据,再加密,最后写入数据呢?难道咱再搞一个子类?
- 咱最好避免这种链式的继承。
3、装饰器模式
- 实现:
- (1)压缩数据 -> 加密数据 -> 写入数据
- (2)读取数据 -> 解密数据 -> 解压数据
- 代码:
public interface DataSource {void writeData(String data);String readData();
}public class FileDataSourceImpl implements DataSource {@Overridepublic void writeData(String data) {System.out.println("[FileDataSourceImpl.writeData] 写入数据");}@Overridepublic String readData() {return "[FileDataSourceImpl.readData] 读取数据";}
}public class EncryptDataSourceImpl implements DataSource {private DataSource dataSource;public EncryptDataSourceImpl(DataSource dataSource) {this.dataSource = dataSource;}@Overridepublic void writeData(String data) {System.out.println("[EncryptFileDataSourceImpl.writeData] 加密数据");dataSource.writeData(data);}@Overridepublic String readData() {System.out.println(dataSource.readData());return "[EncryptFileDataSourceImpl.readData] 解密数据";}
}public class CompressDataSourceImpl implements DataSource {private DataSource dataSource;public CompressDataSourceImpl(DataSource dataSource) {this.dataSource = dataSource;}@Overridepublic void writeData(String data) {System.out.println("[CompressDataSourceImpl.writeData] 压缩数据");dataSource.writeData(data);}@Overridepublic String readData() {System.out.println(dataSource.readData());return "[CompressDataSourceImpl.readData] 解压数据";}
}
@Configuration
public class DataSourceConfig {@Beanpublic DataSource compressDataSourceImpl() {return new CompressDataSourceImpl(new EncryptDataSourceImpl(new FileDataSourceImpl()));}
}
@ComponentScan
public class Application {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Application.class);DataSource dataSource = applicationContext.getBean(DataSource.class);dataSource.writeData("hello world");System.out.println("-----------------------------");System.out.println(dataSource.readData());}
}/*
[CompressDataSourceImpl.writeData] 压缩数据
[EncryptFileDataSourceImpl.writeData] 加密数据
[FileDataSourceImpl.writeData] 写入数据
-----------------------------
[FileDataSourceImpl.readData] 读取数据
[EncryptFileDataSourceImpl.readData] 解密数据
[CompressDataSourceImpl.readData] 解压数据
*/
- 一旦产品经理要改需求了,例如:
- (1)压缩数据 -> 写入数据
- (2)读取数据 -> 解压数据
- 咱只要修改DataSourceConfig即可:
@Configuration
public class DataSourceConfig {@Beanpublic DataSource compressDataSourceImpl() {
// return new CompressDataSourceImpl(new EncryptDataSourceImpl(new FileDataSourceImpl()));return new CompressDataSourceImpl(new FileDataSourceImpl());}
}/*
[CompressDataSourceImpl.writeData] 压缩数据
[FileDataSourceImpl.writeData] 写入数据
-----------------------------
[FileDataSourceImpl.readData] 读取数据
[CompressDataSourceImpl.readData] 解压数据
*/
三、对装饰器模式的思考
1、从代码结构上来看,咋和代理模式这么像呢?
- 装饰器模式:
- (1)实现和被装饰类一样的接口(如上述的:
implements DataSource) - (2)持有被装饰的类(如上述的:
private DataSource dataSource;) - (3)增强接口的方法
- (1)实现和被装饰类一样的接口(如上述的:
- 代理模式:【详见:对代理模式的理解】
- (1)实现和被代理类一样的接口
- (2)持有被代理的类
- (3)增强接口的方法
像,太像了!
- 真的是这样吗?
- 看看客户端是如何使用的吧~
装饰器模式:我们要根据需求,“装饰”出接口对应的实现类。- 通过层层套娃,丰富基础功能。结合上文,从基本的写入数据功能,丰富为:压缩数据 -> 加密数据 -> 写入数据。
代理模式:接口原本的实现类是类A,代理后,客户端真正使用的是实现类B(通常,客户端感知不到这种变化)。
- 看看客户端是如何使用的吧~
- 一图胜前言:
- 一个接口的实现类,从逻辑上说,存在
组合逻辑,例如:- 加密数据 + 写入数据
- 压缩数据 + 写入数据
- 压缩数据 + 加密数据 + 写入数据
- 如果采用继承的方式,会导致定义很多子类,那么用组合吧!用装饰器模式吧!【Java的io便是这种场景~】
- 一个接口的实现类,从逻辑上说,存在
2、设计原则 >> 设计模式
- 我也学了一阵子设计模式了,已经感受到设计模式的局限性了。以上文为例,如果我们拿到的FileDataSourceImpl已经是一坨屎山了,里面写入数据的逻辑并不纯粹,那么,通过装饰器模式丰富写入数据的能力可能会出问题(例如,写入数据前做了一些特殊处理;需求是我们先做特殊处理,再加密后写入;使用装饰器模式就变成了,先加密,然后特殊处理,再写入。)。此时,还不如暴力法来得简洁高效。
破罐子破摔,世界是熵增的…
- 因此,设计模式非常依赖场景。场景稍微变一下,设计模式就失效了… 而真正有用的是,设计模式遵循的设计原则,以及背后的终极奥义:
高内聚,低耦合。
相关文章:
对装饰器模式的理解
目录 一、场景二、面对场景中的新需求,我们怎么办?1、暴力法:直接修改原有的代码。2、子类继承法:既然要增强行为,那我搞一个子类,覆写不就完事了?3、装饰器模式 三、对装饰器模式的思考1、从代…...
在替换微软AD的CA证书服务AD CS前,要先做哪些准备工作?
AD CS是什么 关于这个问题,有几个概念需要先弄明白:PKI、CA、数字证书。 PKI(Public Key Infrastructure,公钥基础设施)是提供公钥加密和数字签名服务的系统或平台,实现基于公钥密码体制的密钥和证书的产生…...
Java中的System
文章目录 概要小结 概要 在Java中,System类提供了一些静态方法来实现与系统相关的操作。以下是System类中常用的方法及其含义: System.currentTimeMillis():返回当前时间(以毫秒为单位)自1970年1月1日00:00:00 GMT以来…...
Mybites一对多collection
Goods实体属性: private List<GoodsImg> goodsImgList; private String id; private String name; GoodsImg实体属性: private String id; private String fid; private String imgpath; …...
基于springboot实现图书进销存管理系统项目【项目源码+论文说明】计算机毕业设计
基于springboot实现图书进销存管理系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了图书进销存管理系统的开发全过程。通过分析图书进销存管理系统管理的不足,创建了一个计算机管理图书进销…...
敏捷开发:想要快速交付就必须舍弃产品质量?
随着敏捷的推广与应用,如今已经成为了最有效的团队级别的方法论,越来越多的软件和 IT 团队正在采用敏捷,但是你在敏捷吗? 自从那一群充满影响力的软件从业者聚集在一起并发布了《敏捷宣言》以来,已经过去了 23 年。敏…...
SNMP-详解指南
目录 SNMP介绍 SNMP的工作机制轮询 SNMP的MIB(管理信息库) SNMP是基于UDP协议 SNMP介绍 SNMP(Simple Network Management Protocol,简单网络管理协议)是一种广泛应用于互联网上的网络管理协议。它提供了一种标准化…...
vue-router 原理【详解】hash模式 vs H5 history 模式
hash 模式 【推荐】 路由效果 在不刷新页面的前提下,根据 URL 中的 hash 值,渲染对应的页面 http://test.com/#/login 登录页http://test.com/#/index 首页 核心API – window.onhashchange 监听 hash 的变化,触发视图更新 window.onhas…...
WebGl/Three 粒子系统 人物破碎及还原运动
粒子 首先,加载模型,这是万千粒子的前身,模型对象由很多面构成,这些面又是由各个点构成的,所以可以将模型的几何体对象geometry赋给粒子对象,粒子物体用Points方式渲染 bloader.load("obj/female02/Fe…...
华为OD-C卷-分披萨[100分]
题目描述 "吃货"和"馋嘴"两人到披萨店点了一份铁盘(圆形)披萨,并嘱咐店员将披萨按放射状切成大小相同的偶数个小块。但是粗心的服务员将披萨切成了每块大小都完全不同奇数块,且肉眼能分辨出大小。 由于两人都想吃到最多的披萨,他们商量了一个他们认…...
uniapp 中video标签视频禁止快,拖拽快进
废话不多说,直接上代码 <video id"myVideo" :src"sectionInfo.type_config.video_url" timeupdate"bindtimeupdate"></video> <script>export default {data() {return {historyTime: 0,}},methods:{// 监听播放进…...
网页端HTML使用MQTTJs订阅RabbitMQ数据
最近在做一个公司的日志组件时有一个问题难住了我。今天问题终于解决了。由于在解决问题中,在网上也查了很多资料都没有一个完整的实例可以参考。所以本着无私分享的目的记录一下完整的解决过程和实例。 需求:做一个统一日志系统可以查看日志列表和一个可…...
课题学习(二十一)----姿态更新的四元数算法推导
声明:本人水平有限,博客可能存在部分错误的地方,请广大读者谅解并向本人反馈错误。 最近需要使用AEKF对姿态进行结算,所以又对四元数进了深入的学习,本篇博客仅对四元数进行推导,后续会对基于四元数的…...
NL2SQL进阶系列(5):论文解读业界前沿方案(DIN-SQL、C3-SQL、DAIL-SQL、SQL-PaLM)、新一代数据集BIRD-SQL解读
NL2SQL进阶系列(5):论文解读业界前沿方案(DIN-SQL、C3-SQL、DAIL-SQL)、新一代数据集BIRD-SQL解读 NL2SQL基础系列(1):业界顶尖排行榜、权威测评数据集及LLM大模型(Spider vs BIRD)全面对比优劣分析[Text2…...
双指针运用:删除重复元素、移除元素
26.删除重复元素 题目描述 给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元…...
什么是三高架构
三高架构是指在软件系统设计与开发中,注重解决高并发性、高可用性和高性能的架构设计模式。 高并发性:指系统能够处理大量并发请求的能力。在高并发场景下,系统需要具备有效的并发处理机制,以保证系统能够快速、准确地响应大量并…...
Unity 对APK签名
关键代码 PS D:\UnityProject\YueJie> jarsigner -verbose -keystore D:\UnityProject\YueJie\user.keystore -signedjar D:\UnityProject\YueJie\meizuemptyapk-release-signed.apk D:\UnityProject\YueJie\MeizuEmpty-release-unsigned.apk 1 示例 # jarsigner的命令格…...
合成孔径雷达干涉测量InSAR数据处理、地形三维重建、形变信息提取、监测等应用
合成孔径雷达干涉测量(Interferometric Synthetic Aperture Radar, InSAR)技术作为一种新兴的主动式微波遥感技术,凭借其可以穿过大气层,全天时、全天候获取监测目标的形变信息等特性,已在地表形变监测、DEM生成、滑坡…...
QT进阶------------------QPushButton(快速添加按钮与使用)
1、解决如何快速的添加按钮 在qt中,通常我们喜欢一个按钮添加一个信号与槽,但是这样写太过浪费时间。要是多个按钮那不是要写30个信号与槽,说实话,我不太喜欢这样。 在ui中,只要拖动按钮,会自动生成按钮的名…...
Vue项目管理器创建项目
黑马程序员JavaWeb开发教程 文章目录 1、创建新项目2、详情3、预设4、功能5、配置6、是否保存为预设模板7、正在创建项目8、创建完成 1、创建新项目 2、详情 3、预设 选择手动,点击下一步 4、功能 只需要额外选择一项–Router 即可,其余的保持默认&a…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...
