




已阅读5页,还剩11页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
从从 Decorator Adapter 模式看模式看 Java IO 库库 我想任何一本介绍模式的书在讲到 Decorator 模式的时候不能不提到它的实际应用 在 Java IO 库里面的应用 这本书也不例外 有点不一样的是 这本书在介绍的时候有个专题 是从两个模式来看 Java IO 库 完这个专题后 个人感觉对 Java IO 库有了全新的认识同时也加深了 Decorator 模式跟 Adapter 适 配器模式的理解 现和大家分享下这个在我看来很伟大的成果 同时说明下 以下大部分文字跟图片是来自 这本书 一一 引子 概括地介绍引子 概括地介绍 Java 的 的 无论是哪种编程语言 输入跟输出都是重要的一部分 Java 也不例外 而且 Java 将输入 输出的功能和使 用范畴做了很大的扩充 它采用了流的机制来实现输入 输出 所谓流 就是数据的有序排列 而流可以是从 某个源 称为流源或 Source of Stream 出来 到某个目的地 称为流汇或 Sink of Stream 去的 由流的方向 可以分成输入流和输出流 一个程序从输入流读取数据向输出流写数据 如 一个程序可以用 FileInputStream 类从一个磁盘文件读取数据 如下图所示 像 FileInputStream 这样的处理器叫做流处理器 它就像流的管道一样 从一个流源吸入某种类型的数据 并 输出某种类型的数据 上面这种示意图叫做流的管道图 同样道理 也可以用 FileOutputStream 类向一个磁盘文件写数据 如下图所示 在实际应用这种机制并不没有太大的用处 程序需要写出地通常是非常结构化的信息 因此这些 byte 类型的 数据实际上是一些数值 文字 源代码等 Java 的 I O 库提供了一个称做链接 Chaining 的机制 可以将一 个流处理器跟另一个流处理器首尾相接 以其中之一的输出为输入 形成一个流管道的链接 例如 DataInputStream 流处理器可以把 FileInputStream 流对象的输出当作输入 将 Byte 类型的数据转换成 Java 的原始类型和 String 类型的数据 如下图所示 类似地 向一个文件写入 Byte 类型的数据不是一个简单的过程 一个程序需要向一个文件里写入的数据往往都 是结构化的 而 Byte 类型则是原始类型 因此在写的时候必须经过转换 DataOutputStream 流处理器提供了 接收了原始数据类型和 String 数据类型 而这个流处理器的输出数据则是 Byte 类型 也就是说 DataOutputStream 可以将源数据转换成 Byte 类型的数据 再输出来 这样一来 就可以将 DataOutputStream 与 FileOutputStream 链接起来 这样程序就可以将原始数据类型和 String 类型的源数据写入这个链接好的双重管道里面 达到将结构化数据写到磁盘文件里面的目的 如下图所示 这又是链接的所发挥的大作用 流处理器所处理的流必定都有流源 而如果将流类所处理的流源分类的话 基本可以分成两大类 第一 数组 String File 等 这一种叫原始流源 第二 同样类型的流用做链接流类的流源 叫链接流源 二 Java I O 库的设计原则 Java 语言的 I O 库是对各种常见的流源 流汇以及处理过程的抽象化 客户端的 Java 程序不必知道最终的流 源 流汇是磁盘上的文件还是数组等 也不必关心数据是否经过缓冲的 可否按照行号读取等处理的细节 书中提到了 对于第一次见到 Java IO 库的人 无不因为这个库的庞杂而感到困惑 而对于熟悉这个库的人 而又常常为这个库的设计是否得当而争论不体 书的作者提出自己的意见 要理解 Java I O 这个庞大而复杂的 库 关键是要掌握两个对称性跟两个设计模式模式 Java I O 库具有两个对称性 它们分别是 输入 输出对称性 比如 InputStream 和 OutputStream 各自占据 Byte 流的输入与输出的两个平行的等 级结构的根部 而 Reader 和 Writer 各自占据 Char 流的输入与输出的两个平行的等级结构的根部 byte char 对称 InputStream 和 Reader 的子类分别负责 Byte 和 Char 流的输入 OutputStream 和 Writer 的子类分别负责 Byte 和 Char 流的输出 它们分别形成平行的等级结构 Java I O 库的两个设计模式 Java 的 I O 库总体设计是符合装饰者模式 Decorator 跟适配器模式 Adapter 的 如前所述 这个库中处 理流的类叫做流类 引子里所谈到的 FileInputStream FileOutputStream DataInputStream 及 DataOutputStream 都是流处理器的例子 装饰者模式 在由 InputStream OutputStream Reader 和 Writer 代表的等级结构内部 有一些流处理器 可以对另一些流处理器起到装饰作用 形成新的 具有改善了的功能的流处理器 装饰者模式是 Java I O 库的 整体设计模式 这样的一个原则是符合装饰者模式的 如下图所示 适配器模式 在由 InputStream OutputStream Reader 和 Writer 代表的等级结构内部 有一些流处理器是 对其它类型的流源的适配 这就是适配器模式的应用 如下图所示 适配器模式应用到了原始流处理器的设计上面 构成了 I O 库所有流处理器的起点 今天晚上先到这了 明天再接着细看两种设计模式具体是怎样在 I O 库中被应用的 三 装饰模式的应用 学过装饰模式后 大家会发现 它在 Java 语言中最著名的应用莫过于 Java I O 标准为库的设计了 这一节将 以处理 Byte 流为例 看看装饰模式是怎样得到应用的 为什么不用继承而用装饰模式为什么不用继承而用装饰模式 我们知道 Java I O 库需要很多性能的各种组合 如果说这些性能的组合是通过继承方式来实现的话 那么每 一种组合都需要一个类 这样就会出现大量重复性问题的出现 从而使类数目 爆炸 而如果采用装饰模式 那 么不仅类的数目大减少了 性能的重复也可以减至到最少 所以装饰模式是 Java I O 库的基本模式 在这里我 想再用 中讲到装饰模式时候的一个例子 看看装饰模式是怎么达到不仅类的数目 大减少了 性能的重复也可以减至到最少 它这个例子大概是说 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 库时达到事半功倍的效果 下面我用 或者是网上看到的一些类图来分析 首先是 InputStream 类型中的装饰模式 InputStream 有七个直接的具体子类 有四个属于 FilterInputStream 的具体子类 如下图所示 上图中所有的类都叫做流处理器 这个图就叫做 InputStream 类型的 流处理器图 书中提到根据输入流的源的类型 可以将这些流类分成两种 即原始流类 Original Stream 和链接流处理 器 Wrapper Stream 原始流处理器原始流处理器 原始流处理器接收一个 Byte 数组对象 String 对象 FileDiscriptor 对象或者不同类型的流源对象 根据上 面的图 原始流处理器包括以下四种 ByteArrayInputStream 为多线程的通信提供缓冲区操作功能 接收一个 Byte 数组作为流的源 FileInputStream 建立一个与文件有关的输入流 接收一个 File 对象作为流的源 PipedInputStream 可以与 PipedOutputStream 配合使用 用于读入一个数据管道的数据 接收一个 PipedOutputStream 作为源 StringBufferInputStream 将一个字符串缓冲区转换为一个输入流 接收一个 String 对象作为流的源 帮助文档上说明 已过时 已过时 此类未能正确地将字符转换为字节 从 1 1 开始 从字符串创建流的 首选方法是通过 StringReader 类进行创建 只有字符串中每个字符的低八位可以由此类使用 链接流处理器链接流处理器 所谓链接流处理器 就是可以接收另一个流对象作为源 并对之进行功能扩展的类 InputStream 类型的链 接处理器包括以下几种 它们都接收另一个 InputStream 对象作为流源 FilterInputStream 称为过滤输入流 它将另一个输入流作为流源 这个类的子类包括以下几种 BufferedInputStream 用来从硬盘将数据读入到一个内存缓冲区中 并从缓冲区提供数据 DataInputStream 提供基于多字节的读取方法 可以读取原始类型的数据 LineNumberInputStream 提供带有行计数功能的过滤输入流 PushbackInputStream 提供特殊的功能 可以将已经读取的字节 推回 到输入流中 ObjectInputStream 可以将使用 ObjectInputStream 串行化的原始数据类型和对象重新并行化 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 I O 库中第二个最为重要的设计模式 InputStream 原始流处理器中的适配器模式原始流处理器中的适配器模式 InputStream类型的原始流处理器是适配器模式的应用 ByteArrayInputStream 是一个适配器类 ByteArrayInputStream 继承了 InputStream 的接口 而封装了一个 byte 数组 换言之 它将一个 byte 数组的 接口适配成 InputStream 流处理器的接口 我们知道 Java 语言支持四种类型 Java 接口 Java 类 Java 数组 原始类型 即 int float 等 前三种是 引用类型 类和数组的实例是对象 原始类型的值不是对象 也即 Java 语言的数组是像所有的其他对象一样的对象 而不管数组中所存储的元素类型是什么 这样一来的话 ByteArrayInputStream 就符合适配器模式的描述 是一个对象形式的适配器类 FileInputStream 是一个适配器类是一个适配器类 在 FileInputStream 继承了 InputStrem 类型 同时持有一个对 FileDiscriptor 的引用 这是将一个 FileDiscriptor 对象适配成 InputStrem 类型的对象形式的适配器模式 如下图所示 查看 JDK1 4 的源代码我们可以看到 PublicPublic classclass FileInputStream extendsextends InputStream File Descriptor handle to the open file privateprivate FileDescriptor fd publicpublic FileInputStream FileDescriptor fdObj SecurityManager security System getSecurityManager ifif fdObj nullnull throwthrow newnew NullPointerException ifif security nullnull security checkRead fdObj fd fdObj publicpublic FileInputStream File file throwsthrows FileNotFoundException String name file getPath SecurityManager security System getSecurityManager ifif security nullnull security checkRead name fd newnew FileDescriptor open name 其它代码 StringBufferInputString 继承了 InputString 类型 同时持有一个对 String 对象的引用 这是一个将 String 对象 适配成 InputString 类型的对象形式的适配器模式 如下图所示 OutputStream 原始流处理器中的适配器模式原始流处理器中的适配器模式 同样地 在 OutputStream 类型中 所有的原始流处理器都是适配器类 ByteArrayOutputStream 继承了 OutputStream 类型 同时持有一个对 byte 数组的引用 它一个 byte 数组的 接口适配成 OutputString 类型的接口 因此也是一个对象形式的适配器模式的应用 FileOutputStream 是一个适配器类是一个适配器类 FileOutputStream 继承了 OutputStream 类型 同时持有一个对 FileDiscriptor 对象的引用 这是一个将 FileDiscriptor 接口适配成 OutputStream 接口形式的对象形适配器模式 Reader 原始流处理器中的适配器模式原始流处理器中的适配器模式 Reader 类型的原始流处理器都是适配器模式的应用 StringReader 是一个适配器类是一个适配器类 StringReader 类继承了 Reader 类型 持有一个对 String 对象的引用 它将 String 的接口适 配成 Reader 类型 的接口 如下图所示 从从 byte 流到流到 char 流的适配流的适配 在 Java I O 库中 使用比较频繁的要数 InputStreamReader OutputStreamWriter 这两种类了 InputStreamReader 是从 byte 输入流到 char 输入流的一个适配器 下图所示就是 InputStreamReader 与 Reader 和 InputStream 等类的结构图 当把 InputStreamReader 与任何 InputStream 的具体子类链接的时候 可以从 InputStream 的输出读入 byte 类 型的数据 将之转换成为 char 类型的数据 如下图所示 查看 JDK1 4 的 InputStreamReader 源代码 publicpublic classclass InputStreamReader extendsextends Reader rivaterivate finalfinal StreamDecoder sd Create an InputStreamReader that uses the default charset param in An InputStream publicpublic InputStreamReader InputStr
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026届上海市师范大学附属中学化学高一第一学期期末联考试题含解析
- 解析卷-青岛版8年级数学下册期末测试卷含答案详解(综合卷)
- 银行借款合同样式
- 职场不抱怨正能量课件
- 职中拳击专业知识培训课件
- 基础强化河南省沁阳市中考数学真题分类(一次函数)汇编同步测试试卷(含答案详解)
- 中外合作经营企业合同
- 创新传播策略引领新媒体时代
- 城市绿化讲座
- 餐饮旅游行业的发展趋势
- 外贸英语专业课件
- 心血管系统疾病相关专业医疗质量控制指标(2021年版)
- 苏教版六年级上册数学教案:19分数与分数相乘及分数乘法练习
- 2025学校食堂食品安全培训
- 生产安全事故应急预案评估报告
- 人教版(2024)七年级下册英语各单元必会重点短语和句型默写版(含答案)
- 人工智能在财务预测中的应用-全面剖析
- 劳动合同标准合同(2025年版)
- 测量不确定度评定第2部分基础知识
- 输液反应应急预案及流程
- T-CDAA 003-2024 大数据应用平台 数据服务运营管理技术要求
评论
0/150
提交评论