Java 装饰器模式(java-io相关源码)

Java IO InputStream家族-装饰器模式

一、介绍

装饰器模式:当一个对象A的功能做不到某些任务时,我们可以通过新建一个新的对象B(装饰器),B继承了A,在这个B中传入A,通过这个A,在B的method()调用A的method()。在准确的需要加强某个功能的时候,可以新建一个对象C去继承B,然后在C的method()调用B的method()并添加相应需要的功能(看起来和代理模式很像)。

因为InputStream有许多子类,假如我们需要使用缓存的方式从文件中读取字节流,就需要FileInputStream、BufferedInputStream互相配合,

		FileInputStream fs=new FileInputStream("某文件绝对路径");
		InputStream inputStream=new BufferedInputStream(fs);
		byte[] bytes=new byte[5];
		while (inputStream.read(bytes)!=-1){
			System.out.println(new String(bytes,0,bytes.length));
		}
		fs.close();

先创建一个FileInputStream对象,然后将它放入BufferedInputStream的构造函数中。
从UML图可以看出FilterInputStream继承于InputStream,BufferedInputStream继承FilterInputStream

二、介绍InputStream和其子类相关源码

此处以read()方法举例
InputStream是一个抽象类

	public abstract class InputStream implements Closeable{
		
		public int read(byte b[]) throws IOException {
	        return read(b, 0, b.length);
	    }
	
		public int read(byte b[], int off, int len) throws IOException {
	        if (b == null) {
	            throw new NullPointerException();
	        } else if (off < 0 || len < 0 || len > b.length - off) {
	            throw new IndexOutOfBoundsException();
	        } else if (len == 0) {
	            return 0;
	        }
	        int c = read();
	        if (c == -1) {
	            return -1;
	        }
	        b[off] = (byte)c;
	        int i = 1;
	        try {
	            for (; i < len ; i++) {
	                c = read();
	                if (c == -1) {
	                    break;
	                }
	                b[off + i] = (byte)c;
	            }
	        } catch (IOException ee) {
	        }
	        return i;
	    }
	}

FilterInputStream(装饰器Decorator)继承了InputStream

	public class FilterInputStream extends InputStream {
		/**
	     * The input stream to be filtered.
	     * 传入InputStream对象
	     */
	    protected volatile InputStream in;

		protected FilterInputStream(InputStream in) {
	        this.in = in;
	    }

		public int read(byte b[]) throws IOException {
	        return read(b, 0, b.length);
	    }

		public int read(byte b[], int off, int len) throws IOException {
			//通过in调用InputStream的read()方法
	        return in.read(b, off, len);
	    }
	}

具体的装饰器角色BufferedInputStream继承FilterInputStream(装饰器)

	public class BufferedInputStream extends FilterInputStream{
		public BufferedInputStream(InputStream in) {
	        this(in, DEFAULT_BUFFER_SIZE);
	    }
	
		public BufferedInputStream(InputStream in, int size) {
			//进入父类的构造器,传入InputStream对象
	        super(in);
	        if (size <= 0) {
	            throw new IllegalArgumentException("Buffer size <= 0");
	        }
	        buf = new byte[size];
	    }

		private byte[] getBufIfOpen() throws IOException {
	        byte[] buffer = buf;
	        if (buffer == null)
	            throw new IOException("Stream closed");
	        //返回一个byte[]数组
	        return buffer;
	    }

		/**
	     * Check to make sure that underlying input stream has not been
	     * nulled out due to close; if not return it;
	     */
	    private InputStream getInIfOpen() throws IOException {
	    	//in:FilterInputStream的属性
	        InputStream input = in;
	        if (input == null)
	            throw new IOException("Stream closed");
	        //返回当前输入流
	        return input;
	    }

		//加强以后的read方法
		public synchronized int read(byte b[], int off, int len) throws IOException{
	        getBufIfOpen(); // Check for closed stream
	        if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
	            throw new IndexOutOfBoundsException();
	        } else if (len == 0) {
	            return 0;
	        }

	        int n = 0;
	        for (;;) {
	            int nread = read1(b, off + n, len - n);
	            if (nread <= 0)
	                return (n == 0) ? nread : n;
	            n += nread;
	            if (n >= len)
	                return n;
	            // if not closed but no bytes available, return
	            InputStream input = in;
	            if (input != null && input.available() <= 0)
	                return n;
	        }
	    }

		//具体加强了的功能
		private int read1(byte[] b, int off, int len) throws IOException {
	        int avail = count - pos;
	        if (avail <= 0) {
	            /* If the requested length is at least as large as the buffer, and
	               if there is no mark/reset activity, do not bother to copy the
	               bytes into the local buffer.  In this way buffered streams will
	               cascade harmlessly. */
	            if (len >= getBufIfOpen().length && markpos < 0) {
	                return getInIfOpen().read(b, off, len);
	            }
	            fill();
	            avail = count - pos;
	            if (avail <= 0) return -1;
	        }
	        int cnt = (avail < len) ? avail : len;
	        /*
	        *将getBufIfOpen()返回的byte[]数组的pos开始复制到b中(从off中),复制长度为cnt
	        */
	        System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
	        pos += cnt;
	        return cnt;
	    }

		private void fill() throws IOException {
	        byte[] buffer = getBufIfOpen();
	        if (markpos < 0)
	            pos = 0;            /* no mark: throw away the buffer */
	        else if (pos >= buffer.length)  /* no room left in buffer */
	            if (markpos > 0) {  /* can throw away early part of the buffer */
	                int sz = pos - markpos;
	                System.arraycopy(buffer, markpos, buffer, 0, sz);
	                pos = sz;
	                markpos = 0;
	            } else if (buffer.length >= marklimit) {
	                markpos = -1;   /* buffer got too big, invalidate mark */
	                pos = 0;        /* drop buffer contents */
	            } else if (buffer.length >= MAX_BUFFER_SIZE) {
	                throw new OutOfMemoryError("Required array size too large");
	            } else {            /* grow buffer */
	                int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
	                        pos * 2 : MAX_BUFFER_SIZE;
	                if (nsz > marklimit)
	                    nsz = marklimit;
	                byte nbuf[] = new byte[nsz];
	                System.arraycopy(buffer, 0, nbuf, 0, pos);
	                if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
	                    // Can't replace buf if there was an async close.
	                    // Note: This would need to be changed if fill()
	                    // is ever made accessible to multiple threads.
	                    // But for now, the only way CAS can fail is via close.
	                    // assert buf == null;
	                    throw new IOException("Stream closed");
	                }
	                buffer = nbuf;
	            }
	        count = pos;
	        /**
	        *FilterInputStream的in属性,调用read()方法
	       	*/
	        int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
	        if (n > 0)
	            count = n + pos;
	    }
	}

三、总结

在整个通过缓存的方式从文件中读取字节流过程中,整个核心还是InputStream(不可缺少的关键),FilterInputStream相当于一个装饰器类,而BufferedInputStream相当于一个具体的装饰类。因为FilterInputStream中已经传入了InputStream in,所以BufferedInputStream可以直接调用对应的输入流和read()方法,再在read()方法中进行方法的增强(read1()),将FileInputStream和BufferedInputStream结合起来大大提高了整个文件读取的速度。这样子,我们在读取文件的时候,可以在不修改InputStream源码的情况下,对功能进行扩展。

注:在网上看了挺多关于装饰器的文章,推荐一篇自以为是比较好的参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值