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

    技术2022-05-20  43

        该模式在java中比较典型的应用也就是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); 

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

     


    最新回复(0)