`
wangyi529
  • 浏览: 34299 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类

Java I/O库的两个设计模式

阅读更多
Java I/O库的两个设计模式:
  Java的I/O库总体设计是符合装饰者模式(Decorator)跟适配器模式(Adapter)的。如前所述,这个库中处理流的类叫做流类。引子里所谈到的 FileInputStream,FileOutputStream,DataInputStream及DataOutputStream都是流处理器的例子。
  1 装饰者模式:在由 InputStream,OutputStream,Reader和Writer代表的等级结构内部,有一些流处理器可以对另一些流处理器起到装饰作用,形成新的,具有改善了的功能的流处理器。装饰者模式是Java I/O库的整体设计模式。这样的一个原则是符合装饰者模式的。

  2 适配器模式:在由InputStream,OutputStream,Reader和Writer代表的等级结构内部,有一些流处理器是对其它类型的流源的适配。这就是适配器模式的应用。
  适配器模式应用到了原始流处理器的设计上面,构成了I/O库所有流处理器的起点。
  JDK为程序员提供了大量的类库,而为了保持类库的可重用性,可扩展性和灵活性,其中使用到了大量的设计模式,本文将介绍JDK的I/O包中使用到的Decorator模式,并运用此模式,实现一个新的输出流类。

  Decorator模式简介

  Decorator模式又名包装器(Wrapper),它的主要用途在于给一个对象动态的添加一些额外的职责。与生成子类相比,它更具有灵活性。

  有时候,我们需要为一个对象而不是整个类添加一些新的功能,比如,给一个文本区添加一个滚动条的功能。我们可以使用继承机制来实现这一功能,但是这种方法不够灵活,我们无法控制文本区加滚动条的方式和时机。而且当文本区需要添加更多的功能时,比如边框等,需要创建新的类,而当需要组合使用这些功能时无疑将会引起类的爆炸。

  我们可以使用一种更为灵活的方法,就是把文本区嵌入到滚动条中。而这个滚动条的类就相当于对文本区的一个装饰。这个装饰(滚动条)必须与被装饰的组件(文本区)继承自同一个接口,这样,用户就不必关心装饰的实现,因为这对他们来说是透明的。装饰会将用户的请求转发给相应的组件(即调用相关的方法),并可能在转发的前后做一些额外的动作(如添加滚动条)。通过这种方法,我们可以根据组合对文本区嵌套不同的装饰,从而添加任意多的功能。这种动态的对对象添加功能的方法不会引起类的爆炸,也具有了更多的灵活性。

  以上的方法就是Decorator模式,它通过给对象添加装饰来动态的添加新的功能。

  Component为组件和装饰的公共父类,它定义了子类必须实现的方法。

  ConcreteComponent是一个具体的组件类,可以通过给它添加装饰来增加新的功能。

  Decorator是所有装饰的公共父类,它定义了所有装饰必须实现的方法,同时,它还保存了一个对于Component的引用,以便将用户的请求转发给Component,并可能在转发请求前后执行一些附加的动作。

  ConcreteDecoratorA和ConcreteDecoratorB是具体的装饰,可以使用它们来装饰具体的Component.

  JAVA IO包中的Decorator模式

  JDK提供的java.io包中使用了Decorator模式来实现对各种输入输出流的封装。以下将以java.io.OutputStream及其子类为例,讨论一下Decorator模式在IO中的使用。

  首先来看一段用来创建IO流的代码:

  以下是代码片段:

  try {

  OutputStream out = new DataOutputStream(new FileOutputStream("test.txt"));

  } catch (FileNotFoundException e) {

  e.printStackTrace();

  }

  这段代码对于使用过JAVA输入输出流的人来说再熟悉不过了,我们使用 DataOutputStream封装了一个FileOutputStream.这是一个典型的Decorator模式的使用,FileOutputStream相当于Component,DataOutputStream就是一个Decorator.将代码改成如下,将会更容易理解:

  以下是代码片段:

  try {

  OutputStream out = new FileOutputStream("test.txt");

  out = new DataOutputStream(out);

  } catch(FileNotFoundException e) {

  e.printStatckTrace();

  }

  由于FileOutputStream和DataOutputStream有公共的父类OutputStream,因此对对象的装饰对于用户来说几乎是透明的。下面就来看看OutputStream及其子类是如何构成Decorator模式的:

  OutputStream是一个抽象类,它是所有输出流的公共父类,其源代码如下:

  以下是代码片段:

  public abstract class OutputStream implements Closeable, Flushable {

  public abstract void write(int b) throws IOException;

  ……

  }

  它定义了write(int b)的抽象方法。这相当于Decorator模式中的Component类。

  ByteArrayOutputStream,FileOutputStream 和 PipedOutputStream 三个类都直接从OutputStream继承,以ByteArrayOutputStream为例:

  以下是代码片段:

  public class ByteArrayOutputStream extends OutputStream {

  protected byte buf[];

  protected int count;

  public ByteArrayOutputStream() {

  this(32);

  }

  public ByteArrayOutputStream(int size) {

  if (size 〈 0) {

  throw new IllegalArgumentException("Negative initial size: "

  + size);

  }

  buf = new byte[size];

  }

  public synchronized void write(int b) {

  int newcount = count + 1;

  if (newcount 〉 buf.length) {

  byte newbuf[] = new byte[Math.max(buf.length 〈〈 1, newcount)];

  System.arraycopy(buf, 0, newbuf, 0, count);

  buf = newbuf;

  }

  buf[count] = (byte)b;

  count = newcount;

  }

  ……

  }

  它实现了OutputStream中的write(int b)方法,因此我们可以用来创建输出流的对象,并完成特定格式的输出。它相当于Decorator模式中的ConcreteComponent类。

  接着来看一下FilterOutputStream,代码如下:

  以下是代码片段:

  public class FilterOutputStream extends OutputStream {

  protected OutputStream out;

  public FilterOutputStream(OutputStream out) {

  this.out = out;

  }

  public void write(int b) throws IOException {

  out.write(b);

  }

  ……

  }

  同样,它也是从OutputStream继承。但是,它的构造函数很特别,需要传递一个OutputStream的引用给它,并且它将保存对此对象的引用。而如果没有具体的OutputStream对象存在,我们将无法创建 FilterOutputStream.由于out既可以是指向FilterOutputStream类型的引用,也可以是指向 ByteArrayOutputStream等具体输出流类的引用,因此使用多层嵌套的方式,我们可以为ByteArrayOutputStream添加多种装饰。这个FilterOutputStream类相当于Decorator模式中的Decorator类,它的write(int b)方法只是简单的调用了传入的流的write(int b)方法,而没有做更多的处理,因此它本质上没有对流进行装饰,所以继承它的子类必须覆盖此方法,以达到装饰的目的。

  BufferedOutputStream 和 DataOutputStream是FilterOutputStream的两个子类,它们相当于Decorator模式中的 ConcreteDecorator,并对传入的输出流做了不同的装饰。以BufferedOutputStream类为例:

  以下是代码片段:

  public class BufferedOutputStream extends FilterOutputStream {

  ……

  private void flushBuffer() throws IOException {

  if (count 〉 0) {

  out.write(buf, 0, count);

  count = 0;

  }

  }

  public synchronized void write(int b) throws IOException {

  if (count 〉= buf.length) {

  flushBuffer();

  }

  buf[count++] = (byte)b;

  }

  ……

  }

  这个类提供了一个缓存机制,等到缓存的容量达到一定的字节数时才写入输出流。首先它继承了FilterOutputStream,并且覆盖了父类的write(int b)方法,在调用输出流写出数据前都会检查缓存是否已满,如果未满,则不写。这样就实现了对输出流对象动态的添加新功能的目的。

  总   结
  在java.io包中,不仅OutputStream用到了Decorator设计模式,InputStream,Reader,Writer等都用到了此模式。而作为一个灵活的,可扩展的类库,JDK中使用了大量的设计模式,比如在 Swing包中的MVC模式,RMI中的Proxy模式等等。对于JDK中模式的研究不仅能加深对于模式的理解,而且还有利于更透彻的了解类库的结构和组成。


更多详细介绍
http://blog.csdn.net/zhytomas/archive/2008/09/22/2963806.aspx
分享到:
评论

相关推荐

    JAVA_API1.6文档(中文)

    java.rmi.registry 提供 RMI 注册表的一个类和两个接口。 java.rmi.server 提供支持服务器端 RMI 的类和接口。 java.security 为安全框架提供类和接口。 java.security.acl 此包中的类和接口已经被 java.security...

    Java NIO:浅析I/O模型

    下面本文先从同步和异步的概念 说起,然后接着阐述了阻塞和非阻塞的区别,接着介绍了阻塞IO和非阻塞IO的区别,然后介绍了同步IO和异步IO的区别,接下来介绍了5种IO模型,后介绍了两种和高性能IO设计相关的设计模式...

    Java 1.6 API 中文 New

    java.rmi.registry 提供 RMI 注册表的一个类和两个接口。 java.rmi.server 提供支持服务器端 RMI 的类和接口。 java.security 为安全框架提供类和接口。 java.security.acl 此包中的类和接口已经被 java.security ...

    java api最新7.0

    java.rmi.registry 提供 RMI 注册表的一个类和两个接口。 java.rmi. 提供支持服务器端 RMI 的类和接口。 java.security 为安全框架提供类和接口。 java.security.acl 此包中的类和接口已经被 java.security 包中的类...

    java jdk-api-1.6 中文 chmd

    java.awt.dnd Drag 和 Drop 是一种直接操作动作,在许多图形用户界面系统中都会遇到它,它提供了一种机制,能够在两个与 GUI 中显示元素逻辑相关的实体之间传输信息。 java.awt.event 提供处理由 AWT 组件所激发的...

    JavaAPI1.6中文chm文档 part1

    java.awt.dnd Drag 和 Drop 是一种直接操作动作,在许多图形用户界面系统中都会遇到它,它提供了一种机制,能够在两个与 GUI 中显示元素逻辑相关的实体之间传输信息。 java.awt.event 提供处理由 AWT 组件所激发的...

    二十三种设计模式【PDF版】

    所以很少存在简单重复的工作,加上Java 代码的精炼性和面向对象纯洁性(设计模式是 java 的灵魂),编程工作将变成一个让你时刻 体验创造快感的激动人心的过程. 为能和大家能共同探讨"设计模式",我将自己在学习中的心得...

    JavaAPI中文chm文档 part2

    java.awt.dnd Drag 和 Drop 是一种直接操作动作,在许多图形用户界面系统中都会遇到它,它提供了一种机制,能够在两个与 GUI 中显示元素逻辑相关的实体之间传输信息。 java.awt.event 提供处理由 AWT 组件所激发的...

    [Java参考文档]

    java.awt.dnd Drag 和 Drop 是一种直接操作动作,在许多图形用户界面系统中都会遇到它,它提供了一种机制,能够在两个与 GUI 中显示元素逻辑相关的实体之间传输信息。 java.awt.event 提供处理由 AWT 组件所激发的...

    java应用软件程序设计

    39 实例17 使用工具提示 42 实例18 不同界面的风格 43 第2章 Java的二维和三维图形处理 45 实例19 颜色处理 46 实例20 合成效果 47 实例21 多种字体效果 49 实例22 合成两个图片 53 实例23 ...

    [Java参考文档].JDK_API 1.6

    java.awt.dnd Drag 和 Drop 是一种直接操作动作,在许多图形用户界面系统中都会遇到它,它提供了一种机制,能够在两个与 GUI 中显示元素逻辑相关的实体之间传输信息。 java.awt.event 提供处理由 AWT 组件所激发的...

    java 面试题 总结

    28、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。 public class ThreadTest1{ private int j; public static ...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    7.5.5 重载容易引发误解的两个地方——返回类型和形参名 170 7.5.6 重载中的最难点——参数匹配原则 171 7.6 使用类的实例作为方法参数 172 7.6.1 超车方法:使用类实例做参数 172 7.6.2 调用这个方法 173 ...

    JAVA面试题最全集

    文件和目录(I/O)操作 如何列出某个目录下的所有文件 如何列出某个目录下的所有子目录 判断一个文件或目录是否存在 如何读写文件 7.Java多态的实现(继承、重载、覆盖) 8.编码转换,怎样实现将GB2312编码的...

    Java 语言基础 —— 非常符合中国人习惯的Java基础教程手册

    两个车轮和齿轮的数目等)和行为(刹车、加速、减速和换档等)。 其次,我们再来看看软件对象。软件对象是现实世界对象的模式化产物,他们也有状态 和行为。软件对象把状态用数据表示并存放在变量里,而行为则用方法...

Global site tag (gtag.js) - Google Analytics