一、装饰者模式的应用场景
装饰者模式(Decorator Pattern)是指在不改变原有对象的基础上,将功能附加到对象上,提供了比继承更有弹性的方案(扩展原有对象的功能),属于结构型模式。装饰者模式适用于以下场景:
- 扩展一个类的功能或给一个类添加附加职责。
- 动态给一个对象天机功能,这些功能可以再动态的撤销。
以做煎饼果子为例演示装饰者模式是怎么装的:
首先做一个煎饼果子抽象:
public abstract class Battercake { protected abstract String getMsg(); protected abstract Integer getPrice(); }
然后,做一个基本的煎饼果子:
public class BaseBattercake extends Battercake{ @Override protected String getMsg() { return "煎饼"; } @Override protected Integer getPrice() { return 5; } }
创建扩展套餐的抽象装饰者:
public class BattercakeDecorator extends Battercake { //静态代理 委派 private Battercake battercake; public BattercakeDecorator(Battercake battercake) { this.battercake = battercake; } @Override protected String getMsg() { return battercake.getMsg(); } @Override protected Integer getPrice() { return battercake.getPrice(); } }
创建加鸡蛋装饰类:
public class EggDecorator extends BattercakeDecorator { public EggDecorator(Battercake battercake) { super(battercake); } @Override protected String getMsg() { return super.getMsg() + "add an egg"; } @Override protected Integer getPrice() { return super.getPrice() + 1; } }
客户端:
public class BattercakeTest { public static void main(String[] args) { //基本版 Battercake battercake = new BaseBattercake(); //加蛋 battercake = new EggDecorator(battercake); //再加 battercake = new EggDecorator(battercake); //跟静态代理区别在于静态代理不是is-a关系 晶体代理会做功能增强,使同一个职责变得不一样 //装饰者模式更多考虑扩展 } }
二、装饰者模式和适配器模式对比
装饰者模式和适配器模式都是包装模式(Wrapper Pattern),装饰者模式是一种特殊的代理模式,二者对比如下:
装饰者模式 | 适配器模式 | |
形式 | 是一种非常特别的适配器 | 没有层级关系,装饰者模式有层级关系 |
定义 | 装饰者和被装饰着实现同一接口,主要目的是为了扩展后依旧保留旧的oop关系 | 适配器和被适配这没有必然的关系,通常采用继承或代理的形式进行包装 |
关系 | 满足is-a关系 | 满足has-a关系 |
功能 | 注重覆盖、扩展 | 注重兼容、转换 |
设计 | 前置考虑 | 后置考虑 |
三、装饰模式在源码中的应用
JDK中的I/O,如BufferReader,InputStream,OutputStream.Spring的缓存,myabtis的TransactionalCache(事物相关缓存):
public class TransactionalCache implements Cache { private static final Log log = LogFactory.getLog(TransactionalCache.class); private final Cache delegate; ... public TransactionalCache(Cache delegate) { this.delegate = delegate; ... } ... }
四、装饰者模式的优缺点
优点:
- 装饰者模式是继承的有力补充,比继承灵活,可以再不原有对象的情况下动态的给一个对象扩展功能,即插即用。
- 使用不同的装饰类及这些装饰类的排列组合,可以实现不同的效果。
- 装饰者模式完全符合开闭原则。
缺点:
- 动态装饰时,多层装饰会更复杂。
- 增加复杂度,复杂度等等吧那些废话。