1.概念
装饰器模式,通过名字来理解就是在原来的类上进行一些装饰,使得原来类的功能更强大,是继承的替代方案;在Java中,InputStream中使用到装饰者模式;下面简单了解下,最后简单说明下在InputStream中的使用;
2.主要结构有几部分组成:
1>Component:抽象组件,定义一组抽象接口,规定这个被装饰类有哪些功能;
2>ConcreteComponent:具体的组件,实现了上面抽象组件的所有功能;
3>Decorator:装饰器角色,持有一个Component的引用;
4>ConcreteDecorator:具体的装饰器角色,负责装饰功能的实现;
3.简单的Demo
1>component抽象组件
public interface Component {
void operation();
}
2>具体的ConcreteComponent组件
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("具体抽象组件的功能");
}
}
3>装饰器角色
public class Decorator implements Component {
protected Component component;
public void setComponent(Component component) {
this.component = component;
}
@Override
public void operation() {
this.component.operation();
}
}
4>具体的装饰器ConcreteDecorator
这里定义了两个装饰器;
public class ConcreteDecoratorA extends Decorator {
@Override
public void operation() {
System.out.println("加上功能A!");
super.operation();
}
}
public class ConcreteDecoratorB extends Decorator {
@Override
public void operation() {
System.out.println("加上功能B!");
super.operation();
}
}
具体使用
public static void main(String[] args) {
Component c = new ConcreteComponent();
ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA();
ConcreteDecoratorB concreteDecoratorB = new ConcreteDecoratorB();
concreteDecoratorA.setComponent(c);
concreteDecoratorA.operation();
concreteDecoratorB.setComponent(concreteDecoratorA);
concreteDecoratorB.operation();
}
返回结果
加上功能A!
具体抽象组件的功能
加上功能B!
加上功能A!
具体抽象组件的功能
注意,这里使用A来构造B的时候,调用会同时具有A和B的功能;
4.InputStream中装饰器角色的使用
首先InputStream是一个顶层的接口,假设有两个实现类FileInputStream和ObjectInputStream分别代表文件字节输入流,对象字节输入流;现在的需求是:
1>要给这两个输入流增加缓冲的功能,按照最直观的方式,分别写一个BufferedInputStream继承这两个类,给它们加上功能
2>给这两个类加上网络的功能,那么再写分别写一个SocketInputStream,继承这两个类,添加上网络功能;
这样存在的问题是:
1>给哪个类加功能就需要扩展它,如果要给这两个类加上缓冲和网络功能,就需要扩展出2*2=4个类,更多的话以此类推,导致类爆炸;
2>代码无法复用,比如要给这两个类加上缓冲功能,那么代码是一样的,但是需要写两遍,如果要修改代码,要修改两个地方,可维护性太差了;
解决方案可以在BufferedInputStream中添加一个引用Inputstream,在BufferedInputStream调用Inputstream中对应的方法,这样扩展代码就可以复用了;下面给出简单的实现
1>InputStream是一个抽象组件
public abstract class InputStream implements Closeable {
// SKIP_BUFFER_SIZE is used to determine the size of skipBuffer
private static final int SKIP_BUFFER_SIZE = 2048;
// skipBuffer is initialized in skip(long), if needed.
private static byte[] skipBuffer;
...
}
2>FileInputStream、ObjectInputStream都是具体构建角色,比如FileInputStream
public class FileInputStream extends InputStream
{
/* File Descriptor - handle to the open file */
private FileDescriptor fd;
private FileChannel channel = null;
...
}
3>FilterInputStream是一个装饰角色,在内部会持有一个InputStream的引用
public class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in;
...
}
4>具体的装饰角色BufferedInputStream、DataInputStream等,比如BufferedInputStream
public class BufferedInputStream extends FilterInputStream {
private static int defaultBufferSize = 8192;
/**
* The internal buffer array where the data is stored. When necessary,
* it may be replaced by another array of
* a different size.
*/
protected volatile byte buf[];
...
}
之后就可以这么来使用了
public static void main(String[] args) throws Exception
{
File file = new File("D:/aaa.txt");
InputStream in0 = new FileInputStream(file);
InputStream in1 = new BufferedInputStream(new FileInputStream(file));
InputStream in2 = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
}
1>in0构建一个文件输入流
2>in1构建一个BufferedInputStream,它给FileInputStream增加了缓冲的功能;
3>in2构建一个DataInputStream,它给FileInputStream增加了DataInputStream功能和BufferedInputStream功能;
总结:装饰器模式与之前的适配器模式是不同的,侧重点不一样:适配器模式将一个不具有某个功能的接口进行改写使得它具有某个功能,使得类可以重复使用;而装饰器模式不是要改变被装饰对象的接口,而是要保留原来的接口,但是在原来的基础上进行了增强或者提高性能;