IO操作是程序中经常遇到的,那java中提供的IO操作有哪些呢?
java中先分成两大类:字节流读写操作(input stream/output stream)和字符流读写操作(reader/writer),流即是对数据输入/输出设备的抽象。
上面提到的四个类是java IO操作的基类,其对应衍生了很多子类,下面基于input stream来说明装饰者模式。
什么是装饰者模式?
俄罗斯套娃大家都非常熟悉,装饰者模式跟俄罗斯套娃就有点像,你想要什么样的娃娃,就可以在原有的基础上套上你要的娃娃的模样,这样你在不改变原来的娃娃的基础上,在外边套上什么娃娃,就变成了什么娃娃。
下面看看IO家族是怎么使用装饰者模式的?
先看看input stream的家族成员
咋一看成员还真多,子孙后代满堂啊,这怎么记得住!诶,这里面可是有名堂的。
先看子代,子代是怎么来的呢?那是很久之前的事了,据说java刚刚被创建的时候就有Input Stream了,作为负责读取数据的始祖,那不同的后代就负责处理来源不同的数据吧:
ByteArrayInputStream负责处理字节数组
FileInputStream负责处理文件
ObjectInputStream负责处理被序列化的对象
PipedInputStream负责处理其他线程的输入流
SequenceInputStream负责处理多个输入流合并成一个流,比如含有流的集合
StringBufferInputStream负责读取StringBuffer中的数据
AudioInputStream负责处理音频流
可是,后来发现从硬盘中读取数据太慢了呀,怎么办?
要不弄个buffer,读取数据时先从buffer中读取,找不到再去硬盘里读,不就快多了吗。可是我每个子类都要拥有这个功能怎么办?在父类中统一实现,不好,如果我在使用buffer时想要跳过几个字节那不是父类又得增加一个方法,我想增加其他功能时,不是父类又要被修改,这样就违反了开闭原则,扩展性实在是太差啦!那怎么办?这就说到装饰着模式了。
就像上面提到的俄罗斯套娃模式,把现有的子类作为实心娃娃,外面套一个BufferInputStream,就拥有了缓冲的功能,套一个DataInputStream,就拥有了从底层输入流读取原始Java数据类型的功能。并且还可以层层嵌套,这样就拥有了各种需要的功能。并且每个子类都能获得全功能还不用每个子类单独去实现,是不是很爽。通过上面的分析,我们可以得出以下结论:
实心娃娃:InputStream子类(除了FilterInputStream)
套娃壳模板:FilterInputStream
套娃壳:FilterInputStream子类
那是如何实现这个模式的呢?
首先,通过套娃壳的构造函数将实心娃娃放进去;
再者,套娃壳+实心娃娃能作为其他壳的实心娃娃;
所以可以看到,套娃壳都继承了InputStream,并且通过构造函数传进去。
那为什么还要FilterInputStream呢,不是让套娃壳直接继承InputStream?
我想大概是InputStream儿子已经很多了,在加那么多壳儿子不合适,而且壳是用来修饰他的儿子的,不是真的他儿子,需要与他的真儿子区分开,于是就有了一个模板儿子,而壳则由模板儿子去生成。
现在看到下面这个例子就很好理解了吧:先读取文件流,然后套上缓冲功能,最后直接将流进行GZIP解压缩,一气呵成
InputStream inputStream = new GZIPInputStream(new BufferedInputStream(new FileInputStream("D:\\temp\\test.txt")));
如有理解错误,请多多指教,谢谢!