简介
我们从扩展类的功能有哪些方法来分析。继承、代理
都可以对原有的类进行增强的操作。但是,如果我们需要在特定的场合加入特定的增强,那就需要装饰者模式
来实现功能。就是可以做到一个可根据需求及特定的场合进行穿配拆卸的增强操作
。
装饰者模式相对比较简单,只需定义好最终被包装的基类
,以及需求对应的增强类
。
引入装饰者模式
我们直接引入装饰者模式进行分析:
接口类(定义一个学习的人抽象接口):
public interface Cake {
void makeCake();
}
实现普通基类:
public class PubCake implements Cake {
@Override
public void makeCake() {
System.out.println("普通蛋糕");
}
}
对蛋糕加水果:
public class Friut implements Cake {
private Cake hardPeople;
public Friut(Cake hardPeople){
super();
this.hardPeople = hardPeople;
}
@Override
public void makeCake() {
System.out.println("加水果");
hardPeople.makeCake();
}
}
对蛋糕加巧克力:
public class AddChookele implements Cake {
private Cake hardPeople;
public AddChookele(Cake hardPeople){
super();
this.hardPeople = hardPeople;
}
@Override
public void makeCake() {
System.out.println("加巧克力");
hardPeople.makeCake();
}
}
Main方法:
public class Main {
public static void main(String[] args) {
Cake cake;
cake = new AddChookele(new Friut(new PubCake()));
cake.makeCake();
}
}
输出结果:
注意事项
- 装饰者模式都是基于套娃的形式,将
增强的需求和实体分离开来
,对应不同的场合在把增强包装进去即可。 - 装饰者模式需要保证一个
原始基类
,即一个毫无装饰的类(例如蛋糕就是在面饼上不断添加奶油,水果等;煮粉就是在简单的粉中不断添加一些青菜,肉等配菜),并且这个毫无装饰的类作为套娃的终结
。 - 我们可以从代码看到
装饰类都会提供一个面向接口的构造方法
,这个构造方法就是将被装饰的实体类
,传入到装饰类中。装饰类在其实现接口的函数最后再调用被装饰类的方法。 - 该模式和代理模式很像,但是代理模式不能根据需求进行动态的对
原始类
进行增强,除非将所有的排列组合都写好,但是会产生类爆炸。 - 一般装饰没有先后顺序,都是对原始基类的模板不断的添加装饰。如果业务需求需要按顺序添加,可自行定义装饰顺序。
UML类图
扩展
装饰者还可以结合委托模式
进行使用。使用了一些继承
,并且完全将原始基类和装饰类拆分开来。下面节点罗列一下步骤。
- 定义抽象被装饰类
- 定义抽象装饰类并继承抽象被装饰类
- 原始基类继承抽象被装饰类
- 其他的各种装饰继承抽象装饰类
- 其他装饰类还是要提供
面向抽象被装饰类的构造方法
,供被装饰者传入。
小结
在JDK的IO流处理中有大量的装饰者模式。
mybatis中对于cache缓存的处理;当我们配置缓存的相应属性时,在mybatis启动扫描后会根据我们配置的属性对cache进行动态的封装(试想如果使用代理或者其他设计模式,就需要把属性结合的各种排列组合列出来,这样会产生类爆炸)。
对于装饰者模式,装饰的类也不必过多。只需根据业务需求合理化即可,否则同样造成类爆炸的问题。
类爆炸:创建的类非常多,至于到了后期项目交接其他人完成时,会让人分不清类的对应。并且在方法区(暂且以JDK1.7为例)中会有很多相应类信息。