1. 程式人生 > >裝飾器模式

裝飾器模式

-- 添加 div implement 它的 pos 能力 數組 filter

簡介

裝飾模式可以在不改變一個對象本身功能的基礎上給對象增加額外的新行為。例如一張照片,我們可以不改變照片本身,給它增加一個相框, 使得它具有防潮的功能;給他增加一個燈管,使它有可以發光的功能...用戶可以根據需要給它增加其它的功能。 在裝飾器模式中,被裝飾的對象叫做Component。 一個Conponent被裝飾後形成的新類對象和原Conponent屬於相同的類別,只是功能有所增強。例如相片被加上相框後,依然屬於相片。

使用裝飾器模式前的基礎代碼

如下,ConcreteComponent是我們程序中使用的組件類。它實現了Component接口。現在想增加ConcreteConponent的功能,怎麽做呢?

技術分享

interface Component
{
      void operation();
}

class ConcreteConponent implements Component
{

      @Override
      public void  operation()
      {
            System . out. println( "我是一個具體組件(ConcreteComponent)對象,我的能力是可以輸出當前這句話" );
      }
}

使用裝飾器模式

能把裝被裝飾對象 具體Component 包裝為 功能更強的類叫做 :裝飾器類。 裝飾器類有2種: 1、抽象裝飾器類 2、具體裝飾器類 抽象裝飾器類
是裝飾器模式核心,也是所有具體裝飾器的父類。它不僅實現了Component,使得所有的具體裝飾器都是一個Componet(is instance of Component),還持有一個Component(保存被裝飾對象的引用),這樣在裝飾器類中就可以使用被裝飾器原來的功能,被裝飾對象可以通過構造函數或則setter註入到裝飾器類中。 具體裝飾器類則負責不同風格的裝飾任務(實現不同的增強邏輯)。 技術分享

測試代碼

interface Component
{
      void operation ();
}

class ConcreteConponent implements
Component { @Override public void operation() { System . out. println( "我是一個具體組件(ConcreteComponent)對象,我的能力是可以輸出當前這句話" ); } } /********************************************************************/ class Decorator implements Component { private Component component; //用於保存被裝飾對象的引用。 public Decorator ( Component component ) //將被裝飾的對象註入到裝飾類中 { this .component = component ; } @Override public void operation() { component .operation (); //保證被裝飾對象的功能不丟失和破壞。 } } /* * 具體裝飾器類SuperComponent * */ class SuperComponent extends Decorator { public SuperComponent ( Component component ) { super (component ); } @Override public void operation() { super .operation (); //保證被裝飾對象的功能不丟失和破壞。 enhance (); } public void enhance() { //增加的功能 System . out. println( "經過裝飾後,我已經被是一個超級組件了!我是在裝飾類(SuperComponent)中額外添加的新功能" ); } } /* * 具體裝飾器類SmartComponent * * */ class SmartComponent extends Decorator { public SmartComponent ( Component component ) { super (component ); } @Override public void operation() { super .operation (); smart (); } public void smart() { //增加的功能 System . out. println( "經過裝飾後,我已經被是一個智能組件了!我是在裝飾類(SmartComponent)中額外添加的新功能" ); } }

客戶端代碼

可以發現,客戶端完全面向抽象編程,不論是具體組件,還是抽象裝飾器,或是具體裝飾器,對於客戶端來說,都是Component。

由於每一個具體裝飾器對象也屬於一個Component,因此我們可以將具體裝飾器再次註入到其它的裝飾器中,進行疊加裝飾。

public static void main (String [] args )
{
            Component normalComponent =  new ConcreteConponent ();     // 一個具體的 普通組件對象
            normalComponent .operation ();


            System . out. println( "---" );


            //將普通組件註入到SuperComponent裝飾器中,裝飾為 超級組件
            Component superComponent   = new SuperComponent (normalComponent );    
            superComponent .operation ();


            System . out. println( "---" );

            //將普通組件註入到SmartComponent裝飾器中,裝飾為 智能組件
            Component smartComponent = new SmartComponent (normalComponent ); 
            smartComponent .operation ();


            System . out. println( "---" );
//將超級組件註入到SmartComponent裝飾器中,裝飾為 智能 超級組件 Component smartAndSuperComponent
= new SmartComponent (superComponent ); smartAndSuperComponent .operation (); }

裝飾器模式在JDK中的運用舉例

我們討論的是Java IO中的 InputStream 、FileInputStream 、 FilterInputStream 、 BufferedInputStream 之間的關系,他們的設計滿足裝飾器模式。

技術分享

FileInputStream

是一個具體的InputStream實例,我們可以使用BufferedInputStream去裝飾他。

InputStream

InputStream就是Component的地位,規定了 具體組件 的接。InputStream中定義了一些read()方法,用於從輸入流中讀取字節數據。我們就拿 裏面的一個 調用一次讀取一個字節的方法為例: 這是一個抽象方法,子類必須實現 : public abstract int read() throws IOException; FilterInputStream JDK文檔對他的描述:
FilterInputStream 包含其他一些輸入流,它將這些流用作其基本數據源,它可以直接傳輸數據或提供一些額外的功能。FilterInputStream 類本身只是簡單地重寫那些將所有請求傳遞給所包含輸入流的 InputStream 的所有方法。FilterInputStream 的子類可進一步重寫這些方法中的一些方法,並且還可以提供一些額外的方法和字段。

他持有了一個InputStream對象引用,且通過構造函數將被裝飾對象InputStream註入,且對read方法進行簡單實現。

public class FilterInputStream extends InputStream {
  
    protected volatile InputStream in ;

    protected FilterInputStream ( InputStream in ) {
        this .in = in ;
    }
    //......
    public int read() throws IOException {
       return in . read();
    }
    
}

BufferedInputStream

JDK文檔對他的描述:
BufferedInputStream 為另一個輸入流添加一些功能,即緩沖輸入以及支持 mark 和 reset 方法的能力。在創建 BufferedInputStream 時,會創建一個內部緩沖區數組。在讀取或跳過流中的字節時,可根據需要從包含的輸入流再次填充該內部緩沖區,一次填充多個字節。mark 操作記錄輸入流中的某個點,reset 操作使得在從包含的輸入流中獲取新字節之前,再次讀取自最後一次 mark 操作後讀取的所有字節。
public class BufferedInputStream extends FilterInputStream
{

    public BufferedInputStream(InputStream in, int size)
    { // 通過構造函數將被裝飾的對象 InputStream 註入
        super(in);
        if (size <= 0)
        {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buf = new byte[size];
    }

    // 增強後的read方法:從緩沖數組中返回讀取的字節數據
    public synchronized int read() throws IOException
    {
        if (pos >= count)
        {
            fill();
            if (pos >= count)
                return -1;
        }
        return getBufIfOpen()[pos++] & 0xff;
    }

    private byte[] getBufIfOpen() throws IOException
    {
        byte[] buffer = buf;
        if (buffer == null)
            throw new IOException("Stream closed");
        return buffer;
    }

    protected volatile byte buf[]; // 內部緩沖輸入數據的字節數組
}

總結

裝飾模式是一種用於替代繼承的技術,它通過一種無須定義子類的方式來給對象動態增加職責,使用對象之間的關聯關系取代類之間的繼承關系。在裝飾模式中引入了裝飾類,在裝飾類中既可以調用待裝飾的原有類的方法,還可以增加新的方法,以擴充原有類的功能。 本文討論的是標準的 透明裝飾器模式,還有一種叫做半透明裝飾器模式,這裏不擴展。 裝飾器模式的優點 (1) 對於擴展一個對象的功能,裝飾模式比繼承更加靈活性,不會導致類的個數急劇增加。 (2) 可以通過一種動態的方式來擴展一個對象的功能,通過配置文件可以在運行時選擇不同的 具體裝飾類,從而實現不同的行為。 (3) 可以對一個對象進行多次裝飾,通過使用不同的具體裝飾類以及這些裝飾類的排列組合, 可以創造出很多不同行為的組合,得到功能更為強大的對象。 (4) 具體構件類與具體裝飾類可以獨立變化,用戶可以根據需要增加新的具體構件類和具體裝飾類,原有類庫代碼無須改變,符合“開閉原則”。 參考:劉偉設計模式

裝飾器模式