天天看点

设计模式-装饰模式(Decorator)在jDK中IO系统的应用

    该模式在java中比较典型的应用也就是jdk的io系统了

    装饰模式类图

设计模式-装饰模式(Decorator)在jDK中IO系统的应用

好吧,其实这类图只对UML熟悉的人才有用,装饰模式有啥用?说白了就是在原来类的功能上,对这些功能做一些增强处理,当然为了增强功能而通过继承也是一种有效的方式,当然对于各种组合比较多的情况下,使用继承可能会有太多的类出现,所以就需要使用装饰模式,当然装饰模式的缺点也是显而易见的,使用上会比较麻烦。

举个例子:

   FileReader

   StringReader

   我要为这两个类的read功能增加缓存功能,如果使用继承方式,我需要两个子类来完成,也许这两个子类得叫BufferedFileReader和BufferedFileStringReader,如果要增加缓存功能的类有十个,那么子类也就需要十个,但是如果用装饰模式,我只要增加一个装饰类既可满足,BufferedReader类,这个就是jdk1.1的io系统设计。

普通的装饰模式简单示例

//总接口

public interface Compoent {

public Object needGirl();

}

//执行类

public class GirlGet implements Compoent {

public Object needGirl() {

// TODO Auto-generated method stub

System.out.println("给你个素颜的女优美眉");

return null;

}

}

//装饰类父类,可有可无

public abstract class Decorator implements Compoent {

public abstract Object needGirl();

}

//装饰类

public class MakeUpDecorator {

private Compoent c = null;

public MakeUpDecorator(Compoent _c) {

this.c = _c;

}

public Object needGirl() {

// 女孩化妆

girlMarkUp();

return c.needGirl();

}

public void girlMarkUp() {

// 化妆

System.out.println("素颜的女优不好,化妆下!");

}

}

//客户端

public class Client {

public static void main(String[] ben){

MakeUpDecorator mud = new MakeUpDecorator(new GirlGet());

mud.needGirl();

}

}

套用io模式的BufferedReader,StringReader,Reader的read功能来做说明:

首先来说明这三个类在上述类图的位置:

Reader:Compoent也是Decorator的基础类

StringReader:ConcreateComponent

BufferedReader:ConcreateDecoratorA

写出简略代码,从jdk1.1中的源码抠出来,去除了很多与该模式无关的代码:

//Reader

public abstract class Reader implements Readable, Closeable {

abstract public int read(char cbuf[], int off, int len) throws IOException;

}

//StringReader

public class StringReader extends Reader {

public int read(char cbuf[], int off, int len) throws IOException {

int n = Math.min(length - next, len);

str.getChars(next, next + n, cbuf, off);

next += n;

return n;

}

}

//BufferedReader

public class BufferedReader extends Reader{

private Reader in = null;

cb = new char[sz];

public BufferedReader(Reader reader)[

in = reader;

}

public int read(char cbuf[], int off, int len) throws IOException

int n = read1(cbuf, off, len);

if (n <= 0)return n;

while ((n < len) && in.ready()) {

int n1 = read1(cbuf, off + n, len - n);

if (n1 <= 0)break;

n += n1;

}

return n;

}

private int read1(char[] cbuf, int off, int len) throws IOException {

if (nextChar >= nChars) {

//当读取的长度超过缓存长度的时候,直接从in里面读取,也就失去了这个装饰类的作用了。

if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {

return in.read(cbuf, off, len);

}

//如果读取的下个字符索引超过了当前的缓存长度,也就是说不在缓存中,那么重新加载下一组缓存.

fill();

}

//当加载缓存后发现,读取的下个字符索引仍旧超过缓存长度,其实就是加载下一组失败,也就是说已经读取完毕了。

if (nextChar >= nChars)return -1;

int n = Math.min(len, nChars - nextChar);

//从缓存中读取字符

System.arraycopy(cb, nextChar, cbuf, off, n);

nextChar += n;

return n;

}

private void fill() throws IOException {

//创建一个缓存,缓存的长度可设置,为设置是默认的

//首先从in中获取指定长度的流到缓存中去。加速访问.

//核心语句就下面一句

n = in.read(cb, dst, cb.length - dst);

}

从上面可以看出,BufferedReader类其实就是将Reader的子类(ConcreateComponent)也就是这里的StingReader的数据放入缓存,然后操作read方法的时候,从缓存中读取,但是实际上的流还是通过StringReader来获取的。也就是说BufferedReader对StringReader类的read功能增加了缓存功能,在事实上,你不使用BufferedReader也可以直接操作StringReader的read功能,只是没有了缓存效果而已。

客户端使用的代码:

String s = "This is the/n/ninternal StringReader buffer./ndderwe"; 

StringReader stringReader = new StringReader(s); 

BufferedReader bufReader = new BufferedReader(stringReader); 

可以看到,客户端使用是比较麻烦的,这就是装饰模式的缺点。

继续阅读