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》

相關文章
相關標籤/搜索