设计方式-装饰模式(Decorator)在jDK中IO系统的应用
该模式在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中的源码抠出来,去除了很多与该模式无关的代码:
- //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);
可以看到,客户端使用是比较麻烦的,这就是装饰模式的缺点。