在学习 Java IO 的时候,记得头几回看到下面的代码,总是有点纳闷:
InputStream inputStream = new BufferedInputStream(new FileInputStream(filePath));
这个代码,首先创建一个 FileInputStream 的对象,然后再传入到 BufferedInputStream 中,这是要干什么,为什么要这么做。
现在回过头来想,当时出现这些疑惑大部分原因是由于:
装饰器模式 主要用于为对象动态的添加功能。比如说,最简单的 IO 使用可能是如下代码:
InputStream inputStream = new FileInputStream(filePath);
但是我们发现,这个代码 每次进行读取都会进行 一次 IO,IO是比较耗费时间的。 那么有没有什么方法降低 IO 次数呢,自然想到了缓冲。那么此时有两种做法:
肯定是第二种好,为什么呢。因为如果你按照1方案,
假如我要定义一个支持X功能,此时要定义一个 专门用于这个功能的stream,这个没有问题;
假如我又要定义一个支持Y功能,此时要定义一个专门用于这个功能的stream,这个也没有问题;
但是,假如我要定义一个 同时支持 X,Y功能,由于不能扩展,所以你必须再定义一个类,同时支持X,Y功能。这个就有问题了,问题就是重复了。
但是,2 方案就能解决这个问题, 2方案中当你需要一个同时支持 X,Y 功能的类,那你动态扩展便是了,不用再新定义一个类,同时支持XY。
这个就是装饰器模式的好处。
简单来说,实现的方式就是:假如我们要为 A类扩展一个功能X,那么我们就定义一个B类,实现了这个X的功能,创建B类的时候,再把A类的一个对象传入到B类的对象中,那么B类对象就拥有了A类对象的所有权,就可以在执行方法前后执行一些方法,用于扩展功能。
再简单一点来说,就是把 A类对象传入B类对象, B类对象都有了A类对象了,那干什么不行。扩展功能自然不在话下。
借用网上的一个图,实现结构就是这样子的:
为什么要搞这么复杂呢,就是为了以后可以更好的扩展。像很多技术我们都知道它的原理,但是你看它们的源码,异常的捕获,各种检测,健壮性,扩展性,别人都考虑得很全,而且已经 code 下来了。不像很多人(包括我),只会动动嘴皮子,要真刀真枪实现的时候,只能呵呵了,借用 Linus 的一句话,’ Talk is cheap, show me the code’,共勉。扯远了,囧。
回到这个图,再对应着下面这个代码说:
InputStream inputStream = new BufferedInputStream(new FileInputStream(filePath));
这样其实就是 给 FileInputStream 添加了一个 缓冲的功能。
以下再给出自定义的代码实现:
public abstract class Component {
public abstract void operation();
}
public class ConcreteComponent extends Component {
public void operation() {
//相应的功能处理
}
}
public abstract class Decorator extends Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
//转发请求给组件对象,可以在转发前后执行一些附加动作
component.operation();
}
}
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
private void operationFirst(){ } //在调用父类的operation方法之前需要执行的操作
private void operationLast(){ } //在调用父类的operation方法之后需要执行的操作
public void operation() {
//调用父类的方法,可以在调用前后执行一些附加动作
operationFirst(); //添加的功能
super.operation(); //这里可以选择性的调用父类的方法,如果不调用则相当于完全改写了方法,实现了新的功能
operationLast(); //添加的功能
}
}
public class Client{
public static void main(String[] args){
Component c1 = new ConcreteComponent (); //首先创建需要被装饰的原始对象(即要被装饰的对象)
Decorator decoratorA = new ConcreteDecoratorA(c1); //给对象透明的增加功能A并调用
decoratorA .operation();
Decorator decoratorB = new ConcreteDecoratorB(c1); //给对象透明的增加功能B并调用
decoratorB .operation();
Decorator decoratorBandA = new ConcreteDecoratorB(decoratorA);//装饰器也可以装饰具体的装饰对象,此时相当于给对象在增加A的功能基础上在添加功能B
decoratorBandA.operation();
}
}
如上代码,关键在于 抽象装饰器类 Decorator 中的维护了一个 Component 对象。这样,在客户端创建的时候,就可以把被装饰者传入到装饰者中,装饰者就有机会对目标进行装饰,也就是扩展功能。
以上就是装饰器模式 个人的一点小小理解。