1、装饰者模式的应用场景
在咱们的生活中好比给煎饼加个鸡蛋,给蛋糕加上一些水果,给房子装修等。为对象扩展一些额外对象的职责。装饰者模式(Decorator Pattern)是指在不改变原有对象的基础之上,提供了比继承更有弹性的替代方案(扩展原有对象的功能)。
缓存
装饰者模式使用于如下几种场景:ide
- 用于扩展一个类的功能或给一个类添加附加职责;
- 动态的给一个对象添加功能,这些功能能够动态的撤销。
1.1 🌮 早餐吃煎饼的装饰者模式
在北京早上通勤上班的同窗们,都有吃过路边摊的煎饼吧。买煎饼的时候可让他给你加个鸡蛋,也能够加香肠,还能够加辣条等。下面咱们用代码来实现下这个生活场景的案例,首先建立一个煎饼 BatterCake 类:测试
public class BatterCake { protected String getMsg() { return "煎饼"; } protected BigDecimal getPrice() { return new BigDecimal(6.00); } }
再建立一个加鸡蛋的煎饼 BatterCakeWithEgg 类:this
public class BatterCakeWithEgg extends BatterCake { @Override protected String getMsg() { return super.getMsg() + "加了1个鸡蛋"; } protected BigDecimal getPrice() { return new BigDecimal(6.00).add(new BigDecimal(1.00)); } }
再建立一个既加鸡蛋又加香肠的 BattercakeWithEggAndSausage 类:code
public class BatterCakeWithEggAndSausage extends BatterCakeWithEgg { @Override protected String getMsg() { return super.getMsg() + "又加了1根香肠"; } @Override protected BigDecimal getPrice() { return super.getPrice().add(new BigDecimal(2.00)); } }
测试main方法:对象
public static void main(String[] args) { Battercake battercake = new Battercake(); System.out.println(battercake.getMsg() + ",总价格:" + battercake.getPrice().doubleValue()); Battercake battercakeWithEgg = new BattercakeWithEgg(); System.out.println(battercakeWithEgg.getMsg() + ",总价格:" + battercakeWithEgg.getPrice().doubleValue()); Battercake battercakeWithEggAndSausage = new BattercakeWithEggAndSausage(); System.out.println(battercakeWithEggAndSausage.getMsg() + ",总价格:" + battercakeWithEggAndSausage.getPrice().doubleValue()); }
运行结果:blog
上面的程序运行结果没有问题,若是须要加2个鸡蛋2个香肠,那么如今实现的方法是没法知足要求的,也没法计算出价格,除非再定制一个类来实现。若是须要一直变显然不科学。下面咱们就用装饰者模式来解决以上问题,首先建立一个抽象的 Battercake 类:继承
public abstract class Battercake { protected abstract String getMsg(); protected abstract BigDecimal getPrice(); }
建立一个基本的煎饼(或者叫基础套餐)BaseBattercake 类:事务
public class BaseBattercake extends Battercake { @Override protected String getMsg() { return "煎饼"; } @Override protected BigDecimal getPrice() { return new BigDecimal(6.00); } }
再建立一个扩展套餐的抽象装饰者 BattercakeDecotator 类:ci
public class BattercakeDecorator extends BaseBattercake { private Battercake battercake; public BattercakeDecorator(Battercake battercake) { this.battercake = battercake; } @Override protected String getMsg() { return this.battercake.getMsg(); } @Override protected BigDecimal getPrice() { return this.battercake.getPrice(); } }
建立鸡蛋装饰者 EggDecorator 类:
public class EggDecorator extends BattercakeDecorator { public EggDecorator(Battercake battercake) { super(battercake); } @Override protected String getMsg() { return super.getMsg() + "加1个鸡蛋"; } @Override protected BigDecimal getPrice() { return super.getPrice().add(new BigDecimal(1.00)); } }
建立香肠装饰者 SausageDecorator 类:
public class SausageDecorator extends BattercakeDecorator { public SausageDecorator(Battercake battercake) { super(battercake); } @Override protected String getMsg() { return super.getMsg() + "加1根香肠"; } @Override protected BigDecimal getPrice() { return super.getPrice().add(new BigDecimal(2.00)); } }
测试代码:
public static void main(String[] args) { Battercake battercake; //路边摊买一个煎饼 battercake = new BaseBattercake(); //煎饼有点小,想再加一个鸡蛋 battercake = new EggDecorator(battercake); //再加一个鸡蛋 battercake = new EggDecorator(battercake); //很饿,再加根香肠 battercake = new SausageDecorator(battercake); System.out.println(battercake.getMsg() + ",总价:" + battercake.getPrice().doubleValue()); }
运行结果:
最后看一下类图:
2、装饰者模式在源码中的体现
2.1 IO相关的类
装饰器模式在源码中也应用得很是多,在 JDK 中体现最明显的类就是 IO 相关的类,如BufferedReader、InputStream、OutputStream,看一下经常使用的 InputStream 的类结构图:
2.2 Spring中的装饰者模式
在 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 的一个包装。 再来看一个 SpringMVC 中的装饰者模式 HttpHeadResponseDecorator 类:
public class HttpHeadResponseDecorator extends ServerHttpResponseDecorator { public HttpHeadResponseDecorator(ServerHttpResponse delegate) { super(delegate); } public final Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { return Flux.from(body).reduce(0, (current, buffer) -> { int next = current + buffer.readableByteCount(); DataBufferUtils.release(buffer); return next; }).doOnNext((count) -> { this.getHeaders().setContentLength((long)count); }).then(); } public final Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) { return this.setComplete(); } }
3、 装饰者模式的优缺点
优势:
-
装饰者是继承的有力补充,比继承灵活,不改变原有对象的状况下动态地给一个对象扩展功能,即插即用;
-
经过使用不一样装饰类以及这些装饰类的排列组合,能够实现不一样效果;
-
装饰者彻底遵照开闭原则。
缺点:
-
会出现更多的代码,更多的类,增长程序复杂性;
-
动态装饰时,多层装饰时会更复杂。