Okay, let’s enter our topic. Today I will share with you the Decorator Mode
in the design mode. Use appropriate life stories and real project scenarios to talk about the design pattern, and finally summarize the design pattern in one sentence.
As the old saying goes: A man relies on his clothes and a horse relies on his saddle. Let us first familiarize ourselves with the background of this sentence:
People rely on clothes, horses rely on saddles, and dogs run with bells for joy. It comes from the tenth chapter of Shen Zijin's "Wanghu Pavilion": "Although In this way, Buddha relies on gold clothing, and people rely on clothing. Dressing up is also very important." Volume 1 of "Awakening the World": Two county magistrates compete for orphans in righteous marriage: "As the saying goes: 'Buddhas rely on gold clothing, and people rely on clothing. The eyes of the world's people are much shallower, and they only have skin and no bones.'" As the saying goes, we say that adults rely on clothes and horses rely on saddles.
This classic story reminds me of a design pattern: the decorator pattern.
What is the decorator pattern? Please listen to Lao Tian speak slowly.
Decorator Pattern is also called Wrapper Pattern ), refers to dynamically adding some additional responsibilities to an object without changing the original object. In terms of adding functionality, the decorator pattern is more flexible than generating subclasses and is a structural design pattern.
English:
Attach additional responsibilities to an object dynamicallykeeping the same interface.Decorators provide a flexible alternative to subclassing for extending functionality.
The decorator pattern provides a more flexible alternative to inheritance ( Extend the functionality of the original object) Attach functionality to the object. Therefore, the core of the decorator pattern is functional extension. Use the decorator pattern to transparently and dynamically extend the functionality of a class.
A rough house looks very ugly before decoration, but as long as With a little decoration, it will be much more beautiful, and it can be used for bathing, sleeping, cooking, etc., but the essence is still a house.
A car was originally a vehicle for transportation, but Mary enlarged it and upgraded its configuration, and then it became a luxury car, but it was still essentially a vehicle for transportation.
A girl was originally very ordinary and average-looking, but after some makeup and some nice clothes, she became a goddess in the hearts of many people.
In short, after some decoration, it is different and its functions are enhanced.
We still use code to implement it. Programmers like to first Make a demo and then study it slowly.
//抽象组件 public abstract class Component { public abstract void operation(); } //具体组件 public class ConcreteComponent extends Component { @Override public void operation() { System.out.println("ConcreteComponent operation"); } } //装饰器抽象 public abstract class Decorator extends Component { protected Component component; public Decorator(Component component) { this.component = component; } @Override public void operation() { component.operation(); } } //具体装饰器 public class ConcreteDecorator extends Decorator { public ConcreteDecorator(Component component) { super(component); } @Override public void operation() { System.out.println("开始前搞点事"); super.operation(); System.out.println("结束后搞点事"); } } //测试 public class Client { public static void main(String[] args) { Component component = new ConcreteDecorator(new ConcreteComponent()); component.operation(); } }
Running results:
开始前搞点事 ConcreteComponent operation 结束后搞点事
The above is the general code implementation of the decorator pattern. Let’s analyze it below.
装饰器模式角色分配符合设计模式的里氏替换原则、依赖倒置原则,从而使得其具备很强的扩展性,最终满足开闭原则。
装饰器模式的实现原理是,让装饰器实现与被装饰类(例如ConcreteComponent)相同的接口(例如Component),使得装饰器与被扩展类类型一致,并在构造函数中传入该接口对象,然后在实现这个接口的被包装类对象的现有功能上添加新功能。由于装饰器与被包装类属于同一类型(均为Component),且构造函数的参数为其实现接口类(Component),因此装饰器模式具备嵌套扩展功能,这样就能使用装饰器模式一层一层地对底层被包装类进行功能扩展了。
在实际开发中,都会存在系统与系统之间的调用,假如说我们现在有个支付功能,现在一切都是没问题的,但是 我们此时需要对发起支付前的请求参数和支付后的相应参数。进行统一处理,原功能不变,只是在原功能上做了一点扩展(增强)。
老功能代码如下:
/** * @author 田先生 * @date 2021-06-02 * * 欢迎关注公众号:java后端技术全栈 */ public interface IOrderPayService { String payment(Long orderId, BigDecimal amount); } public class OrderPayServiceImpl implements IOrderPayService { @Override public String payment(Long orderId, BigDecimal amount) { //先调用余额查询是否足够 System.out.println("发起支付,订单号:" + orderId + ", 支付金额:" + amount.toString()); //调用支付系统 String result = "订单id=" + orderId + "支付完成"; System.out.println("支付结果:" + result); return result; } } public class OrderClient { public static void main(String[] args) { IOrderPayService orderPayService = new OrderPayServiceImpl(); orderPayService.payment(10001L,new BigDecimal("5000")); } }
运行输出:
发起支付,订单号:10001, 支付金额:5000 支付结果:订单id=10001支付完成
新需求,需要把这些请求参数和相应结果进行单独搜集处理,此时为了不影响原有功能,于是我们可以对其进行功能增强。
/** * @author 田先生 * @date 2021-06-02 * * 欢迎关注公众号:java后端技术全栈 */ public class OrderPayDecorator implements IOrderPayService { private IOrderPayService orderPayService; public OrderPayDecorator(IOrderPayService orderPayService) { this.orderPayService = orderPayService; } @Override public String payment(Long orderId, BigDecimal amount) { System.out.println("把这个订单信息(发起支付)" + "订单id=" + orderId + "支付金额=" + amount.toString() + " 【发送给MQ】"); String result = orderPayService.payment(orderId, amount); System.out.println("把订单支付结果信息" + result + " 【发送给MQ】"); return result; } } public class OrderClient { public static void main(String[] args) { IOrderPayService orderPayService =new OrderPayDecorator(new OrderPayServiceImpl()); orderPayService.payment(10001L,new BigDecimal("5000")); } }
运行输出:
把这个订单信息(发起支付)订单id=10001支付金额=5000 【发送给MQ】 发起支付,订单号:10001, 支付金额:5000 支付结果:订单id=10001支付完成 把订单支付结果信息订单id=10001支付完成 【发送给MQ】
整个过程,大家有没有发现,我们并没动原有的代码,仅仅只是做了功能增强。
装饰器模式在新项目中基本上不会用到,通常都是在老项目中使用,因为已有的功能不变,只是做了一些功能增强。
装饰器设计模式在JDK源码、Spring源码以及Mybatis源码中都有。
装饰器模式比较经典的应用就是 JDK 中的 java.io 包下,InputStream、OuputStream、Reader、Writer 及它们的子类。
以 InputStream 为例
UML图
DataInputStream 中构造器入参便是自己的父类(InputStream)。
如果希望提供一个可以读取文件 + 可缓存的字节流,使用继承方式,就需要派生 FileBufferedInputStream;
如果希望提供一个可以读取文件 + 直接读取基本类型的字节流,使用继承方式,就需要派生 FileDataInputStream。
字节流功能的增强还包括支持管道 pipe、字节数组 bytearray、字节对象 object、字节流字符流的转换 等维度,如果用继承方式,那类的层级与种类会多到爆炸。
为了解决问题,这边就使用了装饰器模式。
在Spring中,我们可以尝试理解一下TransactionAwareCacheDecorator类,这个类主要用来处理事务缓存,代码如下。
public class TransactionAwareCacheDecorator implements Cache { private final Cache targetCache; //构造方法入参类型为自己的父类(接口类型) public TransactionAwareCacheDecorator(Cache targetCache) { Assert.notNull(targetCache, "Target Cache must not be null"); this.targetCache = targetCache; } public Cache getTargetCache() { return this.targetCache; } //... }
TransactionAwareCacheDecorator就是对Cache的一个包装,因此,这里也是使用了装饰器模式。
MyBatis中关于Cache和CachingExecutor接口的实现类也使用了装饰者设计模式。Executor是MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护;CachingExecutor是一个Executor的装饰器,给一个Executor增加了缓存的功能。此时可以看做是对Executor类的一个增强,故使用装饰器模式是合适的。
在CachingExecutor 中
public class CachingExecutor implements Executor { //持有组件对象 private Executor delegate; private TransactionalCacheManager tcm = new TransactionalCacheManager(); //构造方法,传入组件对象 public CachingExecutor(Executor delegate) { this.delegate = delegate; delegate.setExecutorWrapper(this); } @Override public int update(MappedStatement ms, Object parameterObject) throws SQLException { //转发请求给组件对象,可以在转发前后执行一些附加动作 flushCacheIfRequired(ms); return delegate.update(ms, parameterObject); } //... }
看完装饰器模式后,你是否有感觉,装饰器模式和代理模式非常的相像,下面我们就来做个对比。
1.装饰器模式可以理解为一种特殊的代理模式。
2.装饰器模式强调自身的功能扩展,透明的扩展(即用户想增强什么功能就增强什么功能),可动态定制的扩展。
3.代理模式强调的是代理过程的控制。
优点
缺点
The above is the detailed content of 3 years of work essential decorator mode. For more information, please follow other related articles on the PHP Chinese website!