结合JDK源码看设计模式——装饰者模式
定义
在不改变原有对象的基础之上,将功能附加到对象上
适用场景
- 扩展一个类的功能
- 动态的给对象增加功能,当功能不需要的时候能够动态删除
详解
在看到定义的时候,可能很多人会想,这不就是继承吗?的确很像,不过是比继承更加有弹性的替代方案。就像原型模式和new之间的关系一样,有区别,但是区别又不是特别大。装饰者一个很重要的词就是动态,他可以灵活的选择要这个功能还是不要。在装饰者中要有四个角色:抽象的实体类,具体的实体类,抽象的装饰者,具体的装饰者。下面画一个大致的UML图
实体类创建之后,如果想扩展实体类那么一般的想法是继承,当然继承也是其中方法之一。上面由UML图就可以看出,在装饰者模式下,我们可以通过装饰类下的扩展功能实现对抽象实体类的包装。当我们需要扩展功能就多加一个扩展功能,不需要扩展功能就不用添加,是一个很动态的扩展方式。下面具体看代码解析。
抽象实体类
public abstract class abstractCake { protected abstract String getCake(); protected abstract int cost(); }
实体类
public class cake extends abstractCake{ @Override protected String getCake() { return "蛋糕"; } @Override protected int cost() { return 100; } }
抽象装饰类(可以抽象也可以不抽象)
public class AbstractDecorator extends abstractCake { private abstractCake abstractcake; public AbstractDecorator(abstractCake abstractcake) { this.abstractcake = abstractcake; } @Override protected String getCake() { return this.abstractcake.getCake(); } @Override protected int cost() { return this.abstractcake.cost(); } }
扩展功能1
public class FruitDecorator extends AbstractDecorator { public FruitDecorator(abstractCake abstractcake) { super(abstractcake); } @Override protected String getCake() { return super.getCake()+" 加一层水果"; } @Override protected int cost() { return super.cost()+20; } }
扩展功能2
public class SugerDecorator extends AbstractDecorator{ public SugerDecorator(abstractCake abstractcake) { super(abstractcake); } @Override protected String getCake() { return super.getCake()+" 多加糖"; } @Override protected int cost() { return super.cost()+10; } }
测试类
public class Test { public static void main(String[] args) { abstractCake ac=new cake(); ac=new FruitDecorator(ac); ac=new SugerDecorator(ac); System.out.println(ac.getCake()); } }
结果
具体的内存图
可以很清楚的看见ac这个抽象类下面一层层包着实体类,解析的时候每一层的包装类的getCake()方法都会送回给抽象实体类,而我的getCake()方法实现的是字符串增加。后面如果我还需要一层水果,那么我就多装饰一次。如果用继承实现,那么我要两层水果,不要糖,那么我就还需要再定义一个实现两层水果的子类,而装饰者模式就只需要修改客户端的ac类实现就行。在JDK中装饰者模式用的最出名的莫过于IO流了,以InputStream为例子。下面是UML图
这就是典型的装饰者。平常我们只需要FileInputStream来读取文件,当我们有一些特殊功能需要,如:BufferedInputStream(完成了缓存功能,使读取文件速度大大提升)和DataInputStream(把byte转换成Java基本数据类型)我们就可以装饰一下InputStream,即灵活又方便。这样使得我们对FileInputStream流的处理更能达到我们想要的预期。当你理解了装饰者模式,我推荐你看这篇博客。这样你就能很好的理解IO流的操作。
总结
装饰者模式是一个比继承更加灵活的扩展方式,要记住装饰者模式必不可少的4个类:抽象的实体类,具体的实体类,抽象的装饰者,具体的装饰者。再结合上面推荐的博客,我相信你不但能理解装饰者,还能更加清晰的理解JDK中的IO流