别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!
点击关注公众号,Java干货及时送达
背景你还在写满屏的爆炸类吗?
就是不管三七二十一,把所有代码写在一个类里面,这样代码不优雅不说,如果改动涉及到老代码,可能还会影响线上的系统稳定性。
其实,很多情况,我们巧妙地利用设计模式就能解决很多潜在的系统问题,今天栈长就教大家使用装饰器模式,在不改动老代码的前提下扩展功能,不但能提升代码优雅性,还能不影响现有的功能,谁用谁知道,真香!!
什么是装饰器模式?装饰器模式,从字面上理解,顾名思义,就是一种装饰模式,它可以在不改动原有代码的情况下,对现有的对象、行为进行新的层次的包装、装饰,增强原有的基本功能以提供更丰富的能力。
举个简单的装修的小例子:
清理 > 刮腻子 > 涂油漆 > 挂壁画
也可以是:
清理 > 刮腻子 > 贴大理石 > 挂电视
或者可以是:
清理 > 刮腻子 > 贴墙纸
这是一步步的简单装修墙面过程(哈哈,大概如此,我不是专业的),这就是装饰器模式,装饰的每个步骤互不干涉,但后面的步骤需要依赖前一个步骤的完成,后面的步骤可以不断在前一个的装饰基础上进行增加。
装饰器模式结构图如下:
装饰器模式类结构如下:
Component:组件接口类,定义被装饰类的基本功能
ConcreteComponent:组件接口的基本实现类
Decorator:装饰器角色类, 实现并持有一个 Component 对象实例
ConcreteDecorator:装饰器的实现类
装饰器模式的优点:
1、不改动原有代码,动态增加功能;
2、对象之间不会相互依赖,松耦合,够优雅;
3、符合开闭原则,扩展性好、便于维护;
装饰器模式的缺点:
1、装饰环节如果很多的话,会造成装饰器类膨胀;
2、装饰器层层嵌套比较复杂,使用者必须清楚所有的装饰器类及其用途;
装饰器模式实战我们把上面的装修的案例用装饰器模式实现一下。
组件接口类:
/***墙面装修接口*@author:栈长*@from:公众号Java技术栈*/publicinterfaceWallBeautify{/***装修操作*@author:栈长*@from:公众号Java技术栈*/voidoperation();}
组件接口的基本实现类:
/***墙面装修基本实现(清理墙面)*@author:栈长*@from:公众号Java技术栈*/publicclassWallBeautifyCleanimplementsWallBeautify{@Overridepublicvoidoperation(){System.out.println("开始清理墙面");}}
装饰器角色类:
这是一个抽象类,实现并持有一个 Component 对象实例,这里使用的是聚合,而不是继承,这也是装饰器模式的要点所在。
/***墙面装修装饰器角色*@author:栈长*@from:公众号Java技术栈*/publicabstractclassWallBeautifyDecoratorimplementsWallBeautify{/***持有一个Component对象实例*@author:栈长*@from:公众号Java技术栈*/privateWallBeautifywallBeautify;publicWallBeautifyDecorator(WallBeautifywallBeautify){this.wallBeautify=wallBeautify;}@Overridepublicvoidoperation(){wallBeautify.operation();decoration();}/***装饰器实现类自定义实现方法*@author:栈长*@from:公众号Java技术栈*/publicabstractvoiddecoration();}
覆写原操作方法,在原操作之后再进行装饰,所以需要提供一个抽象的 decoration 方法供不同的装饰器的实现类去实现。
装饰器的实现类:
这里定义了 3 个装修过程:
刮腻子 > 涂油漆 > 挂壁画
所以各自去继承 装饰器角色类 并实现其装饰方法:
/***墙面装修装饰器角色实现(刮腻子)*@author:栈长*@from:公众号Java技术栈*/publicclassWallBeautifyPuttyextendsWallBeautifyDecorator{publicWallBeautifyPutty(WallBeautifywallBeautify){super(wallBeautify);}@Overridepublicvoiddecoration(){System.out.println("开始刮腻子");}}
/***墙面装修装饰器角色实现(涂油漆)*@author:栈长*@from:公众号Java技术栈*/publicclassWallBeautifyPaintextendsWallBeautifyDecorator{publicWallBeautifyPaint(WallBeautifywallBeautify){super(wallBeautify);}@Overridepublicvoiddecoration(){System.out.println("开始涂油漆");}}
/***墙面装修装饰器角色实现(挂壁画)*@author:栈长*@from:公众号Java技术栈*/publicclassWallBeautifyHangextendsWallBeautifyDecorator{publicWallBeautifyHang(WallBeautifywallBeautify){super(wallBeautify);}@Overridepublicvoiddecoration(){System.out.println("开始挂壁画");}}
测试一下:
/***装饰器模式测试类*@author:栈长*@from:公众号Java技术栈*/publicclassDecoratorTest{publicstaticvoidmain(String[]args){//清理墙面WallBeautifywallBeautifyClean=newWallBeautifyClean();wallBeautifyClean.operation();System.out.println("--------------");//刮腻子WallBeautifywallBeautifyPutty=newWallBeautifyPutty(wallBeautifyClean);wallBeautifyPutty.operation();System.out.println("--------------");//涂油漆WallBeautifywallBeautifyPaint=newWallBeautifyPaint(wallBeautifyPutty);wallBeautifyPaint.operation();System.out.println("--------------");//挂壁画WallBeautifywallBeautifyHang=newWallBeautifyHang(wallBeautifyPaint);wallBeautifyHang.operation();System.out.println("--------------");//多层嵌套WallBeautifywbh=newWallBeautifyHang(newWallBeautifyPaint(newWallBeautifyPutty(newWallBeautifyClean())));wbh.operation();System.out.println("--------------");}}
本节教程所有实战源码已上传到这个仓库:
https://github.com/javastacks/javastack
输出结果:
开始清理墙面--------------开始清理墙面开始刮腻子--------------开始清理墙面开始刮腻子开始涂油漆--------------开始清理墙面开始刮腻子开始涂油漆开始挂壁画--------------开始清理墙面开始刮腻子开始涂油漆开始挂壁画--------------
结果输出正常!
可以看到,装饰器模式的使用还是相对比较简单的,使用装饰器模式可以达到不同的装饰效果,这样即满足了不同客户的需求,而又不用改动原有的代码,还是挺香的。
后续《设计模式》系列文章在公众号Java技术栈陆续更新中,请大家持续关注哦!
装饰器模式在 JDK 中的应用现在我们知道如何使用装饰器模式了,现在我们再看看 JDK 哪些地方运用了装饰器模式呢。
1、IO 流最经典的装饰器模式应用莫过于 JDK 中的 IO 流了(InputStream/ OutputStream)
常用的 InputStream 类结构类如下:
InputStream 和 FileInputStream 是基本的组件接口和实现。
FilterInputStream 就是一个实现组件接口并持有实例引用的装饰器角色:
BufferedInputStream、DataInputStream 都是不同的 FilterInputStream 的装饰实现。
OutputStream 也是同样的原理。
2、同步集合要对非线程安全的集合(如:List、Set)简单提供线程安全的功能,使用装饰器模式也能轻松实现。
来看同步集合工具类方法:
java.util.Collections#synchronizedList(List)
java.util.Collections#synchronizedSet(Set)
它们都是 SynchronizedCollection 的装饰器实现类:
SynchronizedCollection 是装饰器角色:
SynchronizedCollection 实现了集合组件接口并持有集合实例引用,而 Collection(List) 和 ArrayList 是基本的组件接口和实现。
总结本文介绍了装饰器模式的基本概念,也做了一个基本实战,并且举了两个 JDK 中的装饰器模式的例子,相信大家对装饰器模式有了一个基本认识了,怎么运用到项目中,大家应该有谱了吧?
当然,设计模式只是给大家一个设计的参考,并不能盲目运用,否则适得其反。话说,你是怎么在项目中应用装饰器模式的呢?欢迎留言分享案例!
本节教程所有实战源码已上传到这个仓库:
https://github.com/javastacks/javastack
好了,今天的分享就到这里了,后面栈长我会更新其他设计模式的实战文章,公众号Java技术栈第一时间推送。Java技术栈《设计模式》系列文章陆续更新中,请大家持续关注哦!
最后,觉得我的文章对你用收获的话,动动小手,给个在看、转发,原创不易,栈长需要你的鼓励。
开工大吉!再发 10,000 个红包封面2021 年发生的 10 件技术大事!!23 种设计模式实战(很全)换掉 Log4j2!tinylog 横空出世再见单身狗!Java 创建对象的 6 种方式劲爆!Java 协程要来了!重磅官宣:Redis 对象映射框架来了!!推荐一款代码神器,代码量至少省一半!程序员精通各种技术体系,45岁求职难!Spring Boot 3.0 M1 发布,正式弃用 Java 8Spring Boot 学习笔记,这个太全了!版权声明: 本文系公众号 "Java技术栈" 原创,转载、引用本文内容请注明出处,抄袭、洗稿一律投诉侵权,后果自负,并保留追究其法律责任的权利。
关注Java技术栈看更多干货
获取 Spring Boot 实战笔记!相关阅读
-
世界热推荐:今晚7:00直播丨下一个突破...
今晚19:00,Cocos视频号直播马上点击【预约】啦↓↓↓在运营了三年... -
NFT周刊|Magic Eden宣布支持Polygon网...
Block-986在NFT这样的市场,每周都会有相当多项目起起伏伏。在过去... -
环球今亮点!头条观察 | DeFi的兴衰与...
在比特币得到机构关注之后,许多财务专家预测世界将因为加密货币的... -
重新审视合作,体育Crypto的可靠关系才能双赢
Block-987即使在体育Crypto领域,人们的目光仍然集中在FTX上。随着... -
简讯:前端单元测试,更进一步
前端测试@2022如果从2014年Jest的第一个版本发布开始计算,前端开发... -
焦点热讯:刘强东这波操作秀
近日,刘强东发布京东全员信,信中提到:自2023年1月1日起,逐步为...