Java IO设计模式(装饰模式与适配器模式)

01. 装饰模式

1. 定义

Decorator装饰器,就是动态地给一个对象添加一些额外的职责,动态扩展,和下面继承(静态扩展)的比较。所以,装饰器模式具备以下的特征:html

  1. 它必须持有一个被装饰的对象(做为成员变量)。
  2. 它必须拥有与被装饰对象相同的接口(多态调用、扩展须要)。
  3. 它能够给被装饰对象添加额外的功能。

总结:保持接口,动态加强性能。java

装饰器经过包装一个装饰对象来扩展其功能,而又不改变其接口,这其实是基于对象的适配器模式的一种变种。与对象的适配器模式异同:设计模式

  1. 相同点:都拥有一个目标对象。
  2. 不一样点:适配器模式须要实现旧接口,而装饰器模式必须实现相同接口。

适配器模式是在适配器中,重写旧接口的方法来调用新接口方法,来实现旧接口不改变,同时使用新接口的目的。新接口适配旧接口。数组

而装饰模式,是装饰器和旧接口实现相同的接口,在调用新接口的方法中,会调用旧接口的方法,并对其进行扩展。
app

2. 由来(为何不是继承)

功能的拓展,一般可使用继承的方式解决。但这样实现的话,每一种组合都须要一个类,大量重复性内容,类数目“爆炸”;另外,这些拓展的功能必需要是能够预见,编译时就肯定了,静态的扩展。socket

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

若是是按装饰模式的设计思路咱们能够得出下面的设计类图:
性能

装饰模式是怎么达到不只类的数目大减小了,性能的重复也能够减至到最少。this

3. 典型结构图


一句话解释:装饰者和被装饰者须要继承同一个接口或者是抽象类,被装饰者做为装饰者的一个变量。程序中原来调用被装饰者某方法func1的地方改为调用装饰者相同的那个方法func1,而且装饰者的该方法func1上添加了一些额外的功能,在方法func1中再调用被装饰着的方法func1。
这就是动态的扩展。.net

02. 适配器模式

目的:将一个类的接口转换成客户指望的另外一个接口,让本来不兼容的接口能够合做无间。

1. 特色

  1. 适配器对象实现原有接口
  2. 适配器对象组合一个实现新接口的对象(这个对象也能够不实现一个接口,只是一个单纯的对象)
  3. 对适配器原有接口方法的调用被委托给新接口的实例的特定方法(重写旧接口方法来调用新接口功能。)

2.例子

我国国标充电器三孔,德国得标充电器两孔。现去德国旅行。如何将咱们的三孔充电器插入两孔。这就须要适配器。

类图:

DBSocketInterface:德标接口
DBSocket:德国插座(实现DBSocketInterface,提供两孔充电方法)
Hotel : 拥有得标接口。
GBSocketInterface :国标接口
GBSocket : 中国插座(实现GBSocketInterface,提供三孔充电方法)

适配器实现:

public class SocketAdapter    
    implements DBSocketInterface{   //实现旧接口  

    //组合新接口  
    private GBSocketInterface gbSocket;  
      
    /** 
     * 在建立适配器对象时,必须传入一个新街口的实现类 
     */  
    public SocketAdapter(GBSocketInterface gbSocket) {  
        this.gbSocket = gbSocket;  
    }  
      
    /** 
     * 将对就接口的调用适配到新接口 
     */  
    @Override  
    public void powerWithTwoRound() {  
        gbSocket.powerWithThreeFlat();  
    }  

}

在适配器中,继承了旧接口,组合了新接口。在重写旧接口方法的时候,调用了新接口的功能。

hotel.setSocket(socketAdapter);  
 hotel.charge();

在hotel的charge()方法中,调用的是DBSocketInterface 实现子类的两孔充电方法。而这个实现子类,就是适配器类,重写的调用三孔充电的方法。

这也是适配器模式魅力:

不改变原有接口(德标),却还能使用新接口的功能(国标)。

适配器详情和实际使用例子参考《http://blog.csdn.net/zhangjg_blog/article/details/18735243》

03. Java IO 设计模式

1. I/O库对称性

  1. 输入-输出对称:好比InputStream和OutputStream对Byte字节流的输入和输;而Reader和Writer各自占据Char字符流的输入和输出。
  2. byte-char对称:InputStream和Reader的子类分别负责byte和字符流的输入;OutputStream和Writer的子类分别负责byte和字符流的输出。

2.两个设计模式

  1. 装饰模式:在由InputStream、OutputStream、Reader和Writer表明的等级结构内部,有一些流处理器能够对另外一些流处理器起到装饰做用,造成新的、具备改善了的功能的流处理器。
  2. 适配器模式:在由InputStream、OutputStream、Reader和Writer表明的等级结构内部,有一些流处理器是对其余类型的流处理器的适配。这就是适配器的应用。

3.装饰模式的应用

因为java I/O库须要不少性能的各类组合,若是这些性能都是用继承来实现,那么每一种组合都须要一个类,大量重复类。

首先,须要理解java I/O库是由一些原始流处理器和围绕它的装饰流处理器(装饰器,动态扩展原始类性能)所组成的。

这里以InputStream为例,并附上结构图。

这些流类分红两种,即原始流类(Original Stream)和连接流处理器(Wrapper Stream)。

原始流处理器

原始流处理器接收一个Byte数组对象,String对象,FileDiscriptor对象或者不一样类型的流源对象,原始流处理器包括如下四种:

  1. ByteArrayInputStream:接收一个Byte数组做为流的源。
  2. FileInputStream:创建一个与文件有关的输入流。接收一个File对象做为流的源。
  3. PipedInputStream:能够与PipedOutputStream配合使用,用于读入一个数据管道的数据,接收一个PipedOutputStream做为源。
  4. StringBufferInputStream:将一个字符串缓冲区转换为一个输入流。(废弃)

连接流处理器

所谓连接流处理器,就是能够接收另外一个流对象做为源,并对之进行功能扩展的类。InputStream类型的连接处理接收另外一个InputStream对象做为流源。

以FilterInputStream过滤输入流的子类为例。它将另外一个输入流做为流源。这个类的子类包括如下几种:

  1. BufferedInputStream:用来从硬盘将数据读入到一个内存缓冲区中,并从缓冲区提供数据。
  2. DataInputStream:提供基于多字节的读取方法,能够读取原始类型的数据。
  3. LineNumberInputStream:提供带有行计数功能的过滤输入流。
  4. PushbackInputStream:提供特殊的功能,能够将已经读取的字节“推回”到输入流中。

原始流,就是装模式中具体构件角色(被装饰者),连接流,就是装饰模式中的装饰角色。

抽象结构图

一句话总结:连接流处理器,接收原始流处理器并将其做为成员变量引用,都继承了相同的抽象类InputStream。他们在内部工做方法中作了相应改变,在连接流的相同方法中扩展原始流中的方法,这种变化就是装饰模式的目的。

4.适配器模式的应用

StringBufferInputStream是一个适配器类,其继承了InputStream类型,同时持有一个对String类型的引用。这是将处理String对象的新接口适配成InputStream的旧接口的适配器模式。

其他OutputStream、Reader和Writer的装饰模式和适配器模式 参考《http://www.cnblogs.com/wxgblogs/p/5649933.html》 和《http://www.cnblogs.com/heartstage/p/3391070.html》

相关文章
相关标签/搜索