背景
小七的朋友最近有一个烦恼,他想在不改变原有对象的基础上,将功能附加到对象上,问我有没有什么解决方案。小七第一个想到的就是继承和装饰者模式,因为装饰者模式相对继承来说,可以动态的给一个对象添加功能,并且这些功能还可以动态的撤销。
思考过程
假设我们我们有一个平板,它有描述和成本两个属性:
抽象的平板类
public abstract class AbstractTablet {
/**
* 描述
*
* @return {@link String}
*/
protected abstract String getDesc();
/**
* 成本
*
* @return int
*/
protected abstract int cost();
}
实际的平板类
public class Tablet extends AbstractTablet {
/**
* 描述
*
* @return {@link String}
*/
@Override
protected String getDesc() {
return "平板电脑";
}
/**
* 成本
*
* @return int
*/
@Override
protected int cost() {
return 1200;
}
}
然后我们构造一个顶级装饰者 - 平板电脑装饰者,这里有个关键点需要将自己继承的父类通过组合的方式变为自己的属性。
public class TabletDecorator extends AbstractTablet {
/**
* 关键点一:将自己的父类,组合成自己的属性
*/
private AbstractTablet abstractTablet;
public TabletDecorator(AbstractTablet abstractTablet) {
this.abstractTablet = abstractTablet;
}
@Override
protected String getDesc() {
return abstractTablet.getDesc();
}
@Override
protected int cost() {
return abstractTablet.cost();
}
}
具体装饰者一 - 是否可以插SIM卡,这个类需要继承顶级装饰者,并拓展自己的方法
public class TabletSimDecorator extends TabletDecorator {
/**
* 关键点二:子类装饰者调用父类装饰者的构造方法
*
* @param abstractTablet 抽象的平板电脑
*/
public TabletSimDecorator(AbstractTablet abstractTablet) {
super(abstractTablet);
}
/**
* 关键点三:子类装饰者拓展自己的方法
*
* @return {@link String}
*/
@Override
protected String getDesc() {
return super.getDesc() + " 可以插SIM卡";
}
/**
* 关键点三:子类装饰者拓展自己的方法
*
* @return int
*/
@Override
protected int cost() {
return super.cost() + 1000;
}
}
具体装饰者二 - 是否可以拓展内存,这个类也需要继承顶级装饰者,并拓展自己的方法
public class TabletRomDecorator extends TabletDecorator{
/**
* 关键点二:子类装饰者调用父类装饰者的构造方法
*
* @param abstractTablet 抽象的平板电脑
*/
public TabletRomDecorator(AbstractTablet abstractTablet) {
super(abstractTablet);
}
/**
* 关键点三:子类装饰者拓展自己的方法
*
* @return {@link String}
*/
@Override
protected String getDesc() {
return super.getDesc() + " 可以拓展内存";
}
/**
* 关键点三:子类装饰者拓展自己的方法
*
* @return int
*/
@Override
protected int cost() {
return super.cost() + 1000;
}
}
测试类:
public class Test {
public static void main(String[]args){
AbstractTablet abstractTablet;
abstractTablet = new Tablet();
abstractTablet = new TabletSimDecorator(abstractTablet);
abstractTablet = new TabletRomDecorator(abstractTablet);
System.out.println(abstractTablet.getDesc() + ":" + abstractTablet.cost());
}
}
结果:
URL类图
总结
其实装饰者模式很简单,在jdk和开源框架里面也应用得比较广泛,比如说我们最常见的有IO的操作。以BufferedReader为例