背景
你还在写满屏的爆炸类吗?
就是不管三七二十一,把所有代码写在一个类里面,这样代码不优雅不说,如果改动涉及到老代码,可能还会影响线上的系统稳定性。
其实,很多情况,我们巧妙地利用设计模式就能解决很多潜在的系统问题,今天栈长就教大家使用装饰器模式,在不改动老代码的前提下扩展功能,不但能提升代码优雅性,还能不影响现有的功能,谁用谁知道,真香!!
什么是装饰器模式?
装饰器模式,从字面上理解,顾名思义,就是一种装饰模式,它可以在不改动原有代码的情况下,对现有的对象、行为进行新的层次的包装、装饰,增强原有的基本功能以提供更丰富的能力。
举个简单的装修的小例子:
清理 > 刮腻子 > 涂油漆 > 挂壁画
也可以是:
清理 > 刮腻子 > 贴大理石 > 挂电视
或者可以是:
清理 > 刮腻子 > 贴墙纸
这是一步步的简单装修墙面过程(哈哈,大概如此,我不是专业的),这就是装饰器模式,装饰的每个步骤互不干涉,但后面的步骤需要依赖前一个步骤的完成,后面的步骤可以不断在前一个的装饰基础上进行增加。
装饰器模式结构图如下:
装饰器模式类结构如下:
Component:组件接口类,定义被装饰类的基本功能
ConcreteComponent:组件接口的基本实现类
Decorator:装饰器角色类, 实现并持有一个 Component 对象实例
ConcreteDecorator:装饰器的实现类
装饰器模式的优点:
1、不改动原有代码,动态增加功能;
2、对象之间不会相互依赖,松耦合,够优雅;
3、符合开闭原则,扩展性好、便于维护;
装饰器模式的缺点:
1、装饰环节如果很多的话,会造成装饰器类膨胀;
2、装饰器层层嵌套比较复杂,使用者必须清楚所有的装饰器类及其用途;
装饰器模式实战
我们把上面的装修的案例用装饰器模式实现一下。
组件接口类:
/** * 墙面装修接口 * @author: 栈长 * @from: 公众号Java技术栈 */ public interface WallBeautify { /** * 装修操作 * @author: 栈长 * @from: 公众号Java技术栈 */ void operation(); }
组件接口的基本实现类:
/** * 墙面装修基本实现(清理墙面) * @author: 栈长 * @from: 公众号Java技术栈 */ public class WallBeautifyClean implements WallBeautify { @Override public void operation() { System.out.println("开始清理墙面"); } }
装饰器角色类:
这是一个抽象类,实现并持有一个 Component 对象实例,这里使用的是聚合,而不是继承,这也是装饰器模式的要点所在。
/** * 墙面装修装饰器角色 * @author: 栈长 * @from: 公众号Java技术栈 */ public abstract class WallBeautifyDecorator implements WallBeautify { /** * 持有一个 Component 对象实例 * @author: 栈长 * @from: 公众号Java技术栈 */ private WallBeautify wallBeautify; public WallBeautifyDecorator(WallBeautify wallBeautify) { this.wallBeautify = wallBeautify; } @Override public void operation() { wallBeautify.operation(); decoration(); } /** * 装饰器实现类自定义实现方法 * @author: 栈长 * @from: 公众号Java技术栈 */ public abstract void decoration(); }
覆写原操作方法,在原操作之后再进行装饰,所以需要提供一个抽象的 decoration 方法供不同的装饰器的实现类去实现。
装饰器的实现类:
这里定义了 3 个装修过程:
刮腻子 > 涂油漆 > 挂壁画
所以各自去继承 装饰器角色类 并实现其装饰方法:
/** * 墙面装修装饰器角色实现(刮腻子) * @author: 栈长 * @from: 公众号Java技术栈 */ public class WallBeautifyPutty extends WallBeautifyDecorator { public WallBeautifyPutty(WallBeautify wallBeautify) { super(wallBeautify); } @Override public void decoration() { System.out.println("开始刮腻子"); } }
/** * 墙面装修装饰器角色实现(涂油漆) * @author: 栈长 * @from: 公众号Java技术栈 */ public class WallBeautifyPaint extends WallBeautifyDecorator { public WallBeautifyPaint(WallBeautify wallBeautify) { super(wallBeautify); } @Override public void decoration() { System.out.println("开始涂油漆"); } }
/** * 墙面装修装饰器角色实现(挂壁画) * @author: 栈长 * @from: 公众号Java技术栈 */ public class WallBeautifyHang extends WallBeautifyDecorator { public WallBeautifyHang(WallBeautify wallBeautify) { super(wallBeautify); } @Override public void decoration() { System.out.println("开始挂壁画"); } }
测试一下:
/** * 装饰器模式测试类 * @author: 栈长 * @from: 公众号Java技术栈 */ public class DecoratorTest { public static void main(String[] args) { // 清理墙面 WallBeautify wallBeautifyClean = new WallBeautifyClean(); wallBeautifyClean.operation(); System.out.println("--------------"); // 刮腻子 WallBeautify wallBeautifyPutty = new WallBeautifyPutty(wallBeautifyClean); wallBeautifyPutty.operation(); System.out.println("--------------"); // 涂油漆 WallBeautify wallBeautifyPaint = new WallBeautifyPaint(wallBeautifyPutty); wallBeautifyPaint.operation(); System.out.println("--------------"); // 挂壁画 WallBeautify wallBeautifyHang = new WallBeautifyHang(wallBeautifyPaint); wallBeautifyHang.operation(); System.out.println("--------------"); // 多层嵌套 WallBeautify wbh = new WallBeautifyHang(new WallBeautifyPaint( new WallBeautifyPutty(new WallBeautifyClean()))); wbh.operation(); System.out.println("--------------"); } }
本节教程所有实战源码已上传到这个仓库:
输出结果:
开始清理墙面 -------------- 开始清理墙面 开始刮腻子 -------------- 开始清理墙面 开始刮腻子 开始涂油漆 -------------- 开始清理墙面 开始刮腻子 开始涂油漆 开始挂壁画 -------------- 开始清理墙面 开始刮腻子 开始涂油漆 开始挂壁画 --------------
结果输出正常!
可以看到,装饰器模式的使用还是相对比较简单的,使用装饰器模式可以达到不同的装饰效果,这样即满足了不同客户的需求,而又不用改动原有的代码,还是挺香的。