装饰者模式(Decorator pattern),在head first中是这样定义的:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加具有弹性的替代方案。
装饰者的设计原则是:
- 类应该对扩展开放,对修改关闭。
- 多用组合,少用继承。
The decorator pattern can be used to extend (decorate) the functionality of a certain object statically, or in some cases at run-time, independently of other instances of the same class, provided some groundwork is done at design time. This is achieved by designing a new decorator class that wraps the original class. This wrapping could be achieved by the following sequence of steps:
- Subclass the original "Component" class into a "Decorator" class (see UML diagram);
- In the Decorator class, add a Component pointer as a field;
- Pass a Component to the Decorator constructor to initialize the Component pointer;
- In the Decorator class, redirect all "Component" methods to the "Component" pointer; and
- In the ConcreteDecorator class, override any Component method(s) whose behavior needs to be modified.
This pattern is designed so that multiple decorators can be stacked on top of each other, each time adding a new functionality to the overridden method(s).
通过这个图和wiki上的这个描述我们能够很容易理解到修饰模式的精髓,主要体现在"Decorator"上,在原来的类基础上包装起来,变成另外的一个类来使用,每个装饰者中都会附带着一个被装饰者的引用,而且这个引用会作为构造函数的参数进行实例化。上图,component是一个我们抽取出来的抽象组件,一个大家都共有的东西,首先是经过Decorator这个抽象装饰者装饰(也就是Decorator),然后到具体的装饰者ConcreteDecorator进行装饰。也就是在这里对component进行了两次装饰!举一个非常简单的例子如果component是一只小狗,那个Decorat装饰可以算是洗澡,经过 这个洗澡装饰之后,我们就给可以给它其他的更加好的装饰了,比如ConcreteDecorator我们可以理解,给它穿上一件衣服等等。经过各种装饰之后,它就变成了我们心目中可爱的小宠物了。装饰者模式最大一个好处就是,动态的添加修饰,组合修饰,最终达到我们的目的。
下面看,我们伟大的Java里面是怎么使用这种模式的。在java.io类中就隐藏着这种模式。
首先是InputStream.java
public abstract class InputStream implements Closeable {}
这个就相当于我们上图的component类,一个公共的类,抽象出来的组件。
然后我们可以对它进行修饰,首先我们可以使用FilterInputStream.java来进行修饰
public
class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in;
/**
* Creates a <code>FilterInputStream</code>
* by assigning the argument <code>in</code>
* to the field <code>this.in</code> so as
* to remember it for later use.
*
* @param in the underlying input stream, or <code>null</code> if
* this instance is to be created without an underlying stream.
*/
protected FilterInputStream(InputStream in) {
this.in = in;
}
}
这个类主要是用来过滤输入流的。这里能够很清楚的看到两点,首先InputStream的引用在FilterInputStream中出现了,同时InputStream作为构造函数的参数传进来进行实例化。
然后我们再看一个更具体的修饰者,一个我们非常熟悉的IO的类DataInputStream.java,在写读写文件的代码的时候,经常会用到这个类,其实它也是一个装饰者。
public
class DataInputStream extends FilterInputStream implements DataInput {
/**
* Creates a DataInputStream that uses the specified
* underlying InputStream.
*
* @param in the specified input stream
*/
public DataInputStream(InputStream in) {
super(in);
}
}
这个类也通用遵循这修饰模式的原则,引用和构造传参。
既然我们了解了那么多关于这个模式的东西,那我们该怎么使用这个模式呢?下面看我自己写的一点代码。
public class Decorator {
public static void main(String[] args) {
InputStream in = System.in;
InputStream ins = new DataInputStream(in);
ins = new BufferedInputStream(ins);
ins = new PushbackInputStream(ins);
ins = new LineNumberInputStream(ins);
//然后现在的这个ins就具有经过修饰的输入流中的功能了
}
}
修饰模式,我之见解。