学过装饰模式后,大家会发现,它在Java语言中最著名的应用莫过于Java I/O标准为库的设计了。这一节将以处理Byte流为例,看看装饰模式是怎样得到应用的。

 为什么不用继承而用装饰模式

 我们知道Java I/O库需要很多性能的各种组合,如果说这些性能的组合是通过继承方式来实现的话,那么每一种组合都需要一个类,这样就会出现大量重复性问题的出现,从而使类数目“爆炸”。而如果采用装饰模式,那么不仅类的数目大减少了,性能的重复也可以减至到最少。所以装饰模式是Java I/O库的基本模式。在这里我想再用<<Head First Design Pattern>>中讲到装饰模式时候的一个例子,看看装饰模式是怎么达到不仅类的数目大减少了,性能的重复也可以减至到最少:

 它这个例子大概是说:Beverage是一个抽象类,它被所有在一个咖啡店里卖的饮料继承。Beverage有个抽象方法cost,所有的子类都要实现这个抽象方法,计算它们的价格。现在有四个最基本的咖啡:HouseBlend,DarkRoast,Decaf,Espresso他们都继承自Beverage,现在的需求是说在四个最基本的咖啡里,每个都可以随便地添加调味品,像steamed milk,soy,还有mocha最后是加上whipped milk。如果是说按继承来实现这种几个调味品跟原来咖啡的组合的话,我们会很自然地设计来下面的类图来:

看到了上面的类图了吗,我们不禁会说这就是“类爆炸”。如果是按装饰模式的设计思路我们可以得出下面的设计类图:

我们再来看看Gof里面的标准的装饰模式的类图表示:

仔细看看上面的几个图后我们肯定就会理解这句话了:装饰模式是怎么达到不仅类的数目大减少了,性能的重复也可以减至到最少。

 再回到Java I/O库,由于装饰模式的引用,造成了灵活性和复杂都大大增加了,我们在使用Java I/O库时,必须理解Java I/O库是由一些基本的原始流处理器和围绕它们的装饰流处理器所组成的,这样可以在学习和使用Java I/O库时达到事半功倍的效果。

 下面我用<<Java与模式>>,<<Head First Design Pattern>>或者是网上看到的一些类图来分析:

 首先是InputStream类型中的装饰模式:

 InputStream有七个直接的具体子类,有四个属于FilterInputStream的具体子类,如下图所示:

  上图中所有的类都叫做流处理器,这个图就叫做(InputStream类型的)流处理器图。

  书中提到根据输入流的源的类型,可以将这些流类分成两种,即原始流类(Original Stream)和链接流处理器(Wrapper Stream)。

  原始流处理器

  原始流处理器接收一个Byte数组对象,String对象,FileDiscriptor对象或者不同类型的流源对象,根据上面的图,原始流处理器包括以下四种:

  ByteArrayInputStream:为多线程的通信提供缓冲区操作功能,接收一个Byte数组作为流的源。

  FileInputStream:建立一个与文件有关的输入流。接收一个File对象作为流的源。

  PipedInputStream:可以与PipedOutputStream配合使用,用于读入一个数据管道的数据,接收一个PipedOutputStream作为源。

  StringBufferInputStream:将一个字符串缓冲区转换为一个输入流。接收一个String对象作为流的源。(JDK帮助文档上说明:已过时。此类未能正确地将字符转换为字节。从JDK1.1开始,从字符串创建流的首选方法是通过StringReader类进行创建。只有字符串中每个字符的低八位可以由此类使用。)

  链接流处理器

  所谓链接流处理器,就是可以接收另一个流对象作为源,并对之进行功能扩展的类。InputStream类型的链接处理器包括以下几种,它们都接收另一个InputStream对象作为流源。

  (1)FilterInputStream称为过滤输入流,它将另一个输入流作为流源。这个类的子类包括以下几种:

  BufferedInputStream:用来从硬盘将数据读入到一个内存缓冲区中,并从缓冲区提供数据。

  DataInputStream:提供基于多字节的读取方法,可以读取原始类型的数据。

  LineNumberInputStream:提供带有行计数功能的过滤输入流。

  PushbackInputStream:提供特殊的功能,可以将已经读取的字节“推回”到输入流中。

  (2)ObjectInputStream可以将使用ObjectInputStream串行化的原始数据类型和对象重新并行化。

  (3)SeqcueneInputStream可以将两个已有的输入流连接起来,形成一个输入流,从而将多个输入流排列构成一个输入流序列。

  抽象结构图

  按照上面的这种原始流处理器和链接流处理器的划分,可以用下面的结构图来描述它们之间的关系。

  

 上面的流处理器图跟装饰模式的结构图有着显而易见的相同之处。实际上InputStream类型的流处理器结构确实符合装饰模式。 

 装饰模式结构图

 

  对于上图FilterInputStream查看JDK1.4源代码,部分代码如下:

Public class FilterInputStream extends InputStream {
    /**
     * The input stream to be filtered.
     */
    protected InputStream in;
    protected FilterInputStream(InputStream in) {
        this.in = in;
    }
    //其它代码
}
FilterInputStream继承了InputStream,也引用了InputStream,而它有四个子类,这就是所谓的Decorator模式

  上面这个图向我们传达了这个信息:链接流链接流对象接收一个原始流对象或者另外一个链接流对象作为流源;另一方面他们对流源的内部工作方法做了相应的改变,这种改变是装饰模式所要达到的目的。比如:

  BufferedInputStream“装饰”了InputStream的内部工作方式,使得流的读入操作使用了缓冲机制。在使用了缓冲机制后,不会对每一次的流读入操作都产生一个物理的读盘动作,从而提高了程序的效率,在汲及到物理流的读入时,都应当使用这个装饰流类。

  LineNumberInputStream和PushbackInputStream也同样“装饰”了InputStream的内部工作方式,前者使得程序能够按照行号读入数据;后者能够使程序读入的过程中,退后一个字符。

  DataInputStream子类读入各种不同的原始数据类型以及String类型的数据,这一点可以从它提供的各种read方法看出来,如:readByte(),readInt(),readFloat()等。

  Java语言的I/O库提供了四大等级结构:InputStream,OutputStream,Reader,Writer四个系列的类。InputStream和OutputStream处理8位字节流数据, Reader和Writer处理16位的字符流数据。InputStream和Reader处理输入, OutputStream和Writer处理输出,所以OutputStream,Reader,Writer这三类的装饰模式跟前面详细介绍的InputStream装饰模式大同小异,大家可以看书中其它部分对这三类的详细描述或者从网上也能找到有关资料。为了方便比较这几种类型,顺便附上Java语言的I/O层次结构图:

 下面的图表示:以InputStream和OutputStream形成的层次关系

 下面的图表示:以Reader和Writer形成的层次关系

Java IO 流 设计模式的更多相关文章

  1. 【转】java io 流 设计模式

    知识点:什么是装饰模式: http://wenku.baidu.com/view/ad4eac9f51e79b896802263b.html(原理讲的很清楚) http://wenku.baidu.c ...

  2. Java IO 流 -- 设计模式:装饰设计模式

    在java IO 流中我们经常看到这样的写法: ObjectOutputStream oos = new ObjectOutputStream( new BufferedOutputStream(ne ...

  3. Java IO流题库

    一.    填空题 Java IO流可以分为   节点流   和处理流两大类,其中前者处于IO操作的第一线,所有操作必须通过他们进行. 输入流的唯一目的是提供通往数据的通道,程序可以通过这个通道读取数 ...

  4. JAVA.IO流学习笔记

    一.java.io 的描述 通过数据流.序列化和文件系统提供系统输入和输出.IO流用来处理设备之间的数据传输 二.流 流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数 ...

  5. Java IO流01-总叙

     Java IO包体系结构图: 1.流式部分――IO的主体部分: 2.非流式部分——主要包含一些辅助流式部分的类,如:File类.RandomAccessFile类和FileDescriptor等类: ...

  6. java IO流的继承体系和装饰类应用

    java IO流的设计是基于装饰者模式&适配模式,面对IO流庞大的包装类体系,核心是要抓住其功能所对应的装饰类. 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的 ...

  7. Java:IO流与文件基础

    Java:IO流与文件基础 说明: 本章内容将会持续更新,大家可以关注一下并给我提供建议,谢谢啦. 走进流 什么是流 流:从源到目的地的字节的有序序列. 在Java中,可以从其中读取一个字节序列的对象 ...

  8. java IO流详解

    流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  9. Java IO流学习总结

    Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

随机推荐

  1. IE下Date.parse出现NaN有关问题解决

    IE不支持"2000-01-01"这种格式的,但是谷歌浏览器支持,改成"2000/01/01"就可以了. 下面的方法两种浏览器就就都支持了 Date.parse ...

  2. Robotium测试报告的生成方法(上)

    7.1 使用junit-report生成报告 这个是参考网上的:http://www.xuebuyuan.com/2148574.html,经我个人验证是可行的方法,网上写的挺详细的,不过有些不太清楚 ...

  3. JWT实现token的生成和认证demo

    上篇写到对JWT的理解,这篇写一个小的demo来实践下 Github:https://github.com/wuhen152033/token/tree/dev 简介 本次的demo是基于Spring ...

  4. BZOJ2555 SubString 【后缀自动机 + LCT】

    题目 懒得写背景了,给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支持这些操作. 输入 ...

  5. 洛谷P1816 忠诚

    P1816 忠诚 569通过 1.5K提交 题目提供者该用户不存在 标签云端 难度普及+/提高 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨论 主席树的常数貌似大于线段树… TL ...

  6. wordpress install 主题

    手动安装,你可到访WordPress官方网站的主题部分,找到你喜欢的主题后,可压缩下载到电脑并将其解压缩: 上传.zip 包到服务器,解压到 wordpress/wp-content/themes c ...

  7. c#byte数组和string类型转换

    http://blog.csdn.net/rowanhaoa/article/details/42144313/ 用system.text中的encoding这个类

  8. Javaweb测试

    1.建立web 工程 输入Project name.然后点击finish. 2.右键点击WebContent-New-JSP File,新建jsp文件. 3.然后编写一个jsp登录的程序 <%@ ...

  9. vue中通过路由跳转的三种方式

    原文:https://blog.csdn.net/qq_40072782/article/details/82533477 router-view 实现路由内容的地方,引入组件时写到需要引入的地方需要 ...

  10. css 文字垂直居中问题

    CSS 文字垂直居中问题 问题:在 div 中文字居中问题: 当使用 line-height:100%%; 时,文字没有居中,如下: html: <div id="header_log ...