“
人生苦短,不如养狗
作者:Brucebat.Sun
”
一、前言
在前面的章节中我们了解到了Java IO类库的基本概念和部分编程范式,对于基本使用而言,掌握这些基本内容就已经足够了。但是为了更优雅的去使用IO类库甚至是自定义实现IO类库中的接口,我们还需要更进一步的去了解IO类库中使用到设计模式。
二、IO中的设计模式
总的来看,Java IO类库在进行编码设计时使用两种设计模式:装饰者模式和适配器模式。这两种模式均属于结构型模式,也就是说IO类库在进行设计时将关注点放在类和对象的组合上。下面我们就来分别分析一下这两种设计模式在IO类库中的使用。
装饰者模式
使用装饰者模式最大的目的就是在给一个已经存在的对象添加新的功能时,不需要改变现有的数据结构,也即不会出现类的数量爆炸的情况。和一般装饰者模式的使用略有不同的是,IO类库是通过使用一个中间类FilterInputStream
及其子类来实现对于装饰者模式的使用。下面我们通过IO类库中的FilterInputStream
及其子类来看一下装饰者模式的使用情况。
上图是在IO类库中FilterInputStream
及其子类,让我们结合装饰者模式的基本概念及其编程范式先来看一下FilterInputStream
。
public
class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in;
protected FilterInputStream(InputStream in) {
this.in = in;
}
...
}
将其他基本方法刨除之后可以看到,在FilterInputStream
当中引入了一个由外部传入的输入流对象,而这个对象才是FilterInputStream
及其子类实际操作的数据源。
从代码不难看出,这里遵循了设计模式的两个原则。
-
其一,里氏代换原则,也即面向抽象编程。这里引入的对象类并不是某个明确具体的类,而是所有输入流的父类 InputStream
,这也意味着其所有子类均可作为FilterStream
及其子类的数据源。 -
其二,合成复用原则,也即使用组合方式来替代继承。这里使用外部引入的输入流对象作为实际的数据源,在进行对应数据源读取之前, FilterInputSrream
及其子类可以进行额外的数据操作逻辑(是不是感觉有点像代理模式,需要注意这里的逻辑实现是在结构上,而代理模式则是针对对象而言),这里可以简单参考下面的demo案例:
public synchronized int read() throws IOException {
// 进行前置处理
int data = super.read();
// 进行后置处理
return data;
}
相信讲到这里,大家应该能够通过继承FilterInputStream
来实现一个能够对原生的输入流进行一些功能增强的自定义输入流。
适配器模式
适配器模式存在的意义是为了解决两个不兼容接口或者是输出目标对象不兼容的兼容性问题。在实际的IO操作中,我们可能会遇到原始数据为字节流,但是却需要使用到字符流相关的API,这里IO类库为我们提供一个现成的适配器工具InputStreamReader
。这里我们看一下InputStreamReader
的构造函数:
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
public InputStreamReader(InputStream in, String charsetName)
throws UnsupportedEncodingException
{
super(in);
if (charsetName == null)
throw new NullPointerException("charsetName");
sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
}
从上面的两个构造函数我们可以看出,这里实际上是将输入的字节流按照默认的编码集或者指定的编码集进行解码操作,在进行实际读取操作的时候将字节数据转换成字符数据。这部分内容的实现全部放置在了StreamDecoder
当中,这里就不展示具体的代码,有兴趣的同学可以自己阅读一下。在阅读过代码之后会发现,在InputStreamReader
当中真正进行数据读取操作的实际上是内部引入的StreamDecode
对象。
三、总结
至此,关于Java IO的基本内容基本回顾完毕,在这个系列当中笔者没有按照IO类中的类进行逐个讲解,更多的是按照过去未曾细究或者工作实际中遇到的一些点进行分享。后续如果发现其他的知识点会继续在该系列中进行补充。希望通过这个系列能够让大家有所增益。
最后,希望疫情早日过去,世界和平,祝诸君身体健康~~
原文始发于微信公众号(Brucebat的伪技术鱼塘):那些你学了又忘的Java IO(六):设计模式
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/90041.html