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

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

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

    装饰模式类图

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

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

举个例子:

   FileReader

   StringReader

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

普通的装饰模式简单示例

view plain copy to clipboard print ?
  1. //总接口   
  2. public   interface  Compoent {  
  3.     public  Object needGirl();  
  4. }  
  5.   
  6. //执行类   
  7. public   class  GirlGet  implements  Compoent {  
  8.     public  Object needGirl() {  
  9.         // TODO Auto-generated method stub   
  10.         System.out.println("给你个素颜的女优美眉" );  
  11.         return   null ;  
  12.     }  
  13. }  
  14. //装饰类父类,可有可无   
  15. public   abstract   class   Decorator  implements  Compoent {  
  16.     public   abstract  Object needGirl();  
  17. }  
  18. //装饰类   
  19. public   class  MakeUpDecorator {  
  20.     private  Compoent c =  null ;  
  21.     public  MakeUpDecorator(Compoent _c) {  
  22.         this .c = _c;  
  23.     }  
  24.     public  Object needGirl() {  
  25.         // 女孩化妆   
  26.         girlMarkUp();  
  27.         return  c.needGirl();  
  28.     }  
  29.     public   void  girlMarkUp() {  
  30.         // 化妆   
  31.         System.out.println("素颜的女优不好,化妆下!" );  
  32.     }  
  33. }  
  34. //客户端   
  35. public   class  Client {  
  36.     public   static   void  main(String[] ben){  
  37.         MakeUpDecorator mud = new  MakeUpDecorator( new  GirlGet());  
  38.         mud.needGirl();  
  39.     }  
  40. }  
 

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

首先来说明这三个类在上述类图的位置:
Reader:Compoent也是Decorator的基础类

StringReader:ConcreateComponent

BufferedReader:ConcreateDecoratorA

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

 
view plain copy to clipboard print ?
  1. //BufferedReader   
  2. public   class  BufferedReader  extends  Reader{  
  3.    private  Reader in =  null ;  
  4.    cb = new   char [sz];  
  5.    public  BufferedReader(Reader reader)[  
  6.       in = reader;  
  7.    }  
  8.    public   int  read( char  cbuf[],  int  off,  int  len)  throws  IOException  
  9.        int  n = read1(cbuf, off, len);  
  10.        if  (n <=  0 ) return  n;  
  11.        while  ((n < len) && in.ready()) {  
  12.            int  n1 = read1(cbuf, off + n, len - n);  
  13.            if  (n1 <=  0 ) break ;  
  14.            n += n1;  
  15.        }  
  16.        return  n;  
  17.    }  
  18.    private   int  read1( char [] cbuf,  int  off,  int  len)  throws  IOException {  
  19.        if  (nextChar >= nChars) {  
  20.            //当读取的长度超过缓存长度的时候,直接从in里面读取,也就失去了这个装饰类的作用了。   
  21.            if  (len >= cb.length && markedChar <= UNMARKED && !skipLF) {  
  22.                return  in.read(cbuf, off, len);  
  23.            }  
  24.            //如果读取的下个字符索引超过了当前的缓存长度,也就是说不在缓存中,那么重新加载下一组缓存.   
  25.            fill();  
  26.        }  
  27.     //当加载缓存后发现,读取的下个字符索引仍旧超过缓存长度,其实就是加载下一组失败,也就是说已经读取完毕了。   
  28.     if  (nextChar >= nChars) return  - 1 ;  
  29.     int  n = Math.min(len, nChars - nextChar);  
  30.     //从缓存中读取字符   
  31.     System.arraycopy(cb, nextChar, cbuf, off, n);  
  32.     nextChar += n;  
  33.     return  n;  
  34. }  
  35.     private   void  fill()  throws  IOException {  
  36.        //创建一个缓存,缓存的长度可设置,为设置是默认的   
  37.        //首先从in中获取指定长度的流到缓存中去。加速访问.   
  38.        //核心语句就下面一句   
  39.        n = in.read(cb, dst, cb.length - dst);  
  40.     }  
  41. }  
 

从上面可以看出,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); 

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