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

java 裝飾器模式

近期對java的只是做一個整理和複習:發現原來io流是裝飾器模式:具體如下
程式IO的關鍵在於建立BufferedReader物件br:


    BufferedReader br = new BufferedReader(new FileReader("file.txt"));


在建立的過程中,我們先建立了一個FileReader物件,這個物件的功能是從檔案"file.txt"中讀取位元組(byte)流,並轉換為文字流。在Java中,標準的文字編碼方式為unicode。BufferedReader()接收該FileReader物件,並拓展FileReader的功能,新建出一個BufferedReader物件。該物件除了有上述的檔案讀取和轉換的功能外,還提供了快取讀取(buffered)的功能。加強了檔案的讀取和轉換的功能。
最後,我們通過對br物件呼叫readLine()方法,可以逐行的讀取檔案。


(快取讀取是在記憶體中開闢一片區域作為快取,該區域存放FileReader讀出的文字流。當該快取的內容被讀走後(比如readLine()命令),快取會載入後續的文字流。)


BufferedReader()是一個裝飾器(decorator),它接收一個原始的物件,並返回一個經過裝飾的、功能更復雜的物件。修飾器的好處是,它可以用於修飾不同的物件。我們這裡被修飾的是從檔案中讀取的文字流。其他的文字流,比如標準輸入,網路傳輸的流等等,都可以被BufferedReader()修飾,從而實現快取讀取。

Decorator裝飾器,顧名思義,就是動態地給一個物件新增一些額外的職責,就好比為房子進行裝修一樣。因此,裝飾器模式具有如下的特徵:

它必須具有一個裝飾的物件。

它必須擁有與被裝飾物件相同的介面。

它可以給被裝飾物件新增額外的功能。

用一句話總結就是:保持介面,增強效能。

裝飾器通過包裝一個裝飾物件來擴充套件其功能,而又不改變其介面,這實際上是基於物件的介面卡模式的一種變種。它與物件的介面卡模式的異同點如下。

相同點:都擁有一個目標物件。

不同點:介面卡模式需要實現另外一個介面,而裝飾器模式必須實現該物件的介面。

在閻巨集博士的《JAVA與模式》一書中開頭是這樣描述裝飾(Decorator)模式的:

  裝飾模式又名包裝(Wrapper)模式。裝飾模式以對客戶端透明的方式擴充套件物件的功能,是繼承關係的一個替代方案。

裝飾模式的結構

裝飾模式以對客戶透明的方式動態地給一個物件附加上更多的責任。換言之,客戶端並不會覺得物件在裝飾前和裝飾後有什麼不同。裝飾模式可以在不使用創造更多子類的情況下,將物件的功能加以擴充套件。

  裝飾模式的類圖如下:


  在裝飾模式中的角色有:

  ●  抽象構件(Component)角色:給出一個抽象介面,以規範準備接收附加責任的物件。

  ●  具體構件(ConcreteComponent)角色:定義一個將要接收附加責任的類。

  ●  裝飾(Decorator)角色:持有一個構件(Component)物件的例項,並定義一個與抽象構件介面一致的介面。

  ●  具體裝飾(ConcreteDecorator)角色:負責給構件物件“貼上”附加的責任。

具體的例子如下:

我們知道演員其實跟我們一樣,也是普通人,現實裡擔任普通人的角色,在電視上卻無所不能,扮演齊天大聖,皇上等等。

在這裡普通人的角色就是 具體構件角色,扮演的角色就是具體裝飾角色了。

在這裡擴充套件的功能就是 :演的角色了,可以讓大家喜歡看。

我們知道各種模式的一般模式是,實現一個介面:

抽象類構件角色:

package com.java.Decortion;

public interface Player {

	public  void   role();//擔任的角色
	
}
具體構建角色:
package com.java.Decortion;

public class OrginalRole implements Player {

	public OrginalRole(){
		
	}

	@Override
	public void role() {

		System.out.println("具體構件角色:丈夫,父親,兒子,演員,平民。");

	}

}

裝飾角色:
package com.java.Decortion;

public class DecoPlayer implements Player {

	Player player;

	public DecoPlayer(Player player) {

		this.player = player;

	}

	@Override
	public void role() {

		player.role();
	}

}

具體裝飾角色:
package com.java.Decortion;

public class DetialDecPlayer extends DecoPlayer {

	public DetialDecPlayer(Player player) {
		
		super(player);
		
	}

	@Override
	public void role() {

		super.role();
		System.out.println("具體要裝扮的角色:孫悟空!");
		
		
	}

}

客戶端呼叫:
package com.java.Decortion;

public class DecoTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

           OrginalRole  or=new OrginalRole();
           
            DetialDecPlayer   de=new DetialDecPlayer(or);
            
            de.role();
           
           
	}

}

執行結果:

具體構件角色:丈夫,父親,兒子,演員,平民。
具體要裝扮的角色:孫悟空!


以下內容來自網路轉載:

裝飾模式的簡化

  大多數情況下,裝飾模式的實現都要比上面給出的示意性例子要簡單。

  如果只有一個ConcreteComponent類,那麼可以考慮去掉抽象的Component類(介面),把Decorator作為一個ConcreteComponent子類。如下圖所示:

 

  如果只有一個ConcreteDecorator類,那麼就沒有必要建立一個單獨的Decorator類,而可以把Decorator和ConcreteDecorator的責任合併成一個類。甚至在只有兩個ConcreteDecorator類的情況下,都可以這樣做。如下圖所示:

 

透明性的要求

  裝飾模式對客戶端的透明性要求程式不要宣告一個ConcreteComponent型別的變數,而應當宣告一個Component型別的變數。

  用孫悟空的例子來說,必須永遠把孫悟空的所有變化都當成孫悟空來對待,而如果把老孫變成的魚兒當成魚兒,而不是老孫,那就被老孫騙了,而這時不應當發生的。下面的做法是對的:

TheGreatestSage sage = new Monkey();
TheGreatestSage bird = new Bird(sage);

  這段程式碼的意思是隻能使用TheGreatestSage裡面定義的方法。

而下面的做法是不對的:

Monkey sage = new Monkey();
Bird bird = new Bird(sage);

這段程式碼的意思是使用各自定義的方法。

半透明的裝飾模式

  然而,純粹的裝飾模式很難找到。裝飾模式的用意是在不改變介面的前提下,增強所考慮的類的效能。在增強效能的時候,往往需要建立新的公開的方法。即便是在孫大聖的系統裡,也需要新的方法。比如齊天大聖類並沒有飛行的能力,而鳥兒有。這就意味著鳥兒應當有一個新的fly()方法。再比如,齊天大聖類並沒有游泳的能力,而魚兒有,這就意味著在魚兒類裡應當有一個新的swim()方法。

  這就導致了大多數的裝飾模式的實現都是“半透明”的,而不是完全透明的。換言之,允許裝飾模式改變介面,增加新的方法。這意味著客戶端可以宣告ConcreteDecorator型別的變數,從而可以呼叫ConcreteDecorator類中才有的方法:

TheGreatestSage sage = new Monkey();
Bird bird = new Bird(sage);
bird.fly();

  完全的裝飾模式應該是 介面不變,強化介面的功能,但是上面的程式碼中,子類鳥兒增加了flay()的功能,父類可以向下轉型進行呼叫,相當於改變了裝飾角色的介面,增加了新的方法。稱之為半透明。

半透明的裝飾模式是介於裝飾模式和介面卡模式之間的。介面卡模式的用意是改變所考慮的類的介面,也可以通過改寫一個或幾個方法,或增加新的方法來增強或改變所考慮的類的功能。大多數的裝飾模式實際上是半透明的裝飾模式,這樣的裝飾模式也稱做半裝飾、半介面卡模式。

裝飾模式的優點

  (1)裝飾模式與繼承關係的目的都是要擴充套件物件的功能,但是裝飾模式可以提供比繼承更多的靈活性。裝飾模式允許系統動態決定“貼上”一個需要的“裝飾”,或者除掉一個不需要的“裝飾”。繼承關係則不同,繼承關係是靜態的,它在系統執行前就決定了。

  (2)通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可以創造出很多不同行為的組合。

裝飾模式的缺點

  由於使用裝飾模式,可以比使用繼承關係需要較少數目的類。使用較少的類,當然使設計比較易於進行。但是,在另一方面,使用裝飾模式會產生比使用繼承關係更多的物件。更多的物件會使得查錯變得困難,特別是這些物件看上去都很相像。


裝飾模式的優點

  (1)裝飾模式與繼承關係的目的都是要擴充套件物件的功能,但是裝飾模式可以提供比繼承更多的靈活性。裝飾模式允許系統動態決定“貼上”一個需要的“裝飾”,或者除掉一個不需要的“裝飾”。繼承關係則不同,繼承關係是靜態的,它在系統執行前就決定了。

  (2)通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可以創造出很多不同行為的組合。

裝飾模式的缺點

  由於使用裝飾模式,可以比使用繼承關係需要較少數目的類。使用較少的類,當然使設計比較易於進行。但是,在另一方面,使用裝飾模式會產生比使用繼承關係更多的物件。更多的物件會使得查錯變得困難,特別是這些物件看上去都很相像。

設計模式在JAVA I/O庫中的應用

  裝飾模式在Java語言中的最著名的應用莫過於Java I/O標準庫的設計了。

  由於Java I/O庫需要很多效能的各種組合,如果這些效能都是用繼承的方法實現的,那麼每一種組合都需要一個類,這樣就會造成大量效能重複的類出現。而如果採用裝飾模式,那麼類的數目就會大大減少,效能的重複也可以減至最少。因此裝飾模式是Java I/O庫的基本模式。

  Java I/O庫的物件結構圖如下,由於Java I/O的物件眾多,因此只畫出InputStream的部分。

  根據上圖可以看出:

  ●  抽象構件(Component)角色:由InputStream扮演。這是一個抽象類,為各種子型別提供統一的介面。

  ●  具體構件(ConcreteComponent)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStream等類扮演。它們實現了抽象構件角色所規定的介面。

  ●  抽象裝飾(Decorator)角色:由FilterInputStream扮演。它實現了InputStream所規定的介面。

  ●  具體裝飾(ConcreteDecorator)角色:由幾個類扮演,分別是BufferedInputStream、DataInputStream以及兩個不常用到的類LineNumberInputStream、PushbackInputStream。

 半透明的裝飾模式

  裝飾模式和介面卡模式都是“包裝模式(Wrapper Pattern)”,它們都是通過封裝其他物件達到設計的目的的,但是它們的形態有很大區別。

  理想的裝飾模式在對被裝飾物件進行功能增強的同時,要求具體構件角色、裝飾角色的介面與抽象構件角色的介面完全一致。而介面卡模式則不然,一般而言,介面卡模式並不要求對源物件的功能進行增強,但是會改變源物件的介面,以便和目標介面相符合。

  裝飾模式有透明和半透明兩種,這兩種的區別就在於裝飾角色的介面與抽象構件角色的介面是否完全一致。透明的裝飾模式也就是理想的裝飾模式,要求具體構件角色、裝飾角色的介面與抽象構件角色的介面完全一致。相反,如果裝飾角色的介面與抽象構件角色介面不一致,也就是說裝飾角色的介面比抽象構件角色的介面寬的話,裝飾角色實際上已經成了一個介面卡角色,這種裝飾模式也是可以接受的,稱為“半透明”的裝飾模式,如下圖所示。

  在介面卡模式裡面,介面卡類的介面通常會與目標類的介面重疊,但往往並不完全相同。換言之,介面卡類的介面會比被裝飾的目標類介面寬。

  顯然,半透明的裝飾模式實際上就是處於介面卡模式與裝飾模式之間的灰色地帶。如果將裝飾模式與介面卡模式合併成為一個“包裝模式”的話,那麼半透明的裝飾模式倒可以成為這種合併後的“包裝模式”的代表。

InputStream型別中的裝飾模式

  InputStream型別中的裝飾模式是半透明的。為了說明這一點,不妨看一看作裝飾模式的抽象構件角色的InputStream的原始碼。這個抽象類聲明瞭九個方法,並給出了其中八個的實現,另外一個是抽象方法,需要由子類實現。

複製程式碼
public abstract class InputStream implements Closeable {

    public abstract int read() throws IOException;

 
    public int read(byte b[]) throws IOException {}

    public int read(byte b[], int off, int len) throws IOException {}

    public long skip(long n) throws IOException {}

    public int available() throws IOException {}
    
    public void close() throws IOException {}
    
    public synchronized void mark(int readlimit) {}
    
    public synchronized void reset() throws IOException {}

    public boolean markSupported() {}

}
複製程式碼

  下面是作為裝飾模式的抽象裝飾角色FilterInputStream類的原始碼。可以看出,FilterInputStream的介面與InputStream的介面是完全一致的。也就是說,直到這一步,還是與裝飾模式相符合的。

複製程式碼
public class FilterInputStream extends InputStream {
    protected FilterInputStream(InputStream in) {}
    
    public int read() throws IOException {}

    public int read(byte b[]) throws IOException {}
    
    public int read(byte b[], int off, int len) throws IOException {}

    public long skip(long n) throws IOException {}

    public int available() throws IOException {}

    public void close() throws IOException {}

    public synchronized void mark(int readlimit) {}

    public synchronized void reset() throws IOException {}

    public boolean markSupported() {}
}
複製程式碼

  下面是具體裝飾角色PushbackInputStream的原始碼。

複製程式碼
public class PushbackInputStream extends FilterInputStream {
    private void ensureOpen() throws IOException {}
    
    public PushbackInputStream(InputStream in, int size) {}

    public PushbackInputStream(InputStream in) {}

    public int read() throws IOException {}

    public int read(byte[] b, int off, int len) throws IOException {}

    public void unread(int b) throws IOException {}

    public void unread(byte[] b, int off, int len) throws IOException {}

    public void unread(byte[] b) throws IOException {}

    public int available() throws IOException {}

    public long skip(long n) throws IOException {}

    public boolean markSupported() {}

    public synchronized void mark(int readlimit) {}
 
    public synchronized void reset() throws IOException {}

    public synchronized void close() throws IOException {}
}
複製程式碼

   檢視原始碼,你會發現,這個裝飾類提供了額外的方法unread(),這就意味著PushbackInputStream是一個半透明的裝飾類。換言 之,它破壞了理想的裝飾模式的要求。如果客戶端持有一個型別為InputStream物件的引用in的話,那麼如果in的真實型別是 PushbackInputStream的話,只要客戶端不需要使用unread()方法,那麼客戶端一般沒有問題。但是如果客戶端必須使用這個方法,就 必須進行向下型別轉換。將in的型別轉換成為PushbackInputStream之後才可能呼叫這個方法。但是,這個型別轉換意味著客戶端必須知道它 拿到的引用是指向一個型別為PushbackInputStream的物件。這就破壞了使用裝飾模式的原始用意。

  現實世界與理論總歸是有一段差距的。純粹的裝飾模式在真實的系統中很難找到。一般所遇到的,都是這種半透明的裝飾模式。

  下面是使用I/O流讀取檔案內容的簡單操作示例。

複製程式碼
public class IOTest {

    public static void main(String[] args) throws IOException {
        // 流式讀取檔案
        DataInputStream dis = null;
        try{
            dis = new DataInputStream(
                    new BufferedInputStream(
                            new FileInputStream("test.txt")
                    )
            );
            //讀取檔案內容
            byte[] bs = new byte[dis.available()];
            dis.read(bs);
            String content = new String(bs);
            System.out.println(content);
        }finally{
            dis.close();
        }
    }

}
複製程式碼

  觀察上面的程式碼,會發現最裡層是一個FileInputStream物件,然後把它傳遞給一個BufferedInputStream物件,經過BufferedInputStream處理,再把處理後的物件傳遞給了DataInputStream物件進行處理,這個過程其實就是裝飾器的組裝過程,FileInputStream物件相當於原始的被裝飾的物件,而BufferedInputStream物件和DataInputStream物件則相當於裝飾器。


相關推薦

Java裝飾模式(Decorator)

一、概述       裝飾模式又名包裝(Wrapper)模式。裝飾模式以對客戶端透明的方式擴充套件物件的功能,可以在不建立更多子類的情況下,將物件的功能加以擴充套件,是繼承關係的一個替代方案。用意:動態地為物件新增一些額外的功能,就好比為房子進行裝修一樣。       特點

java 裝飾模式

近期對java的只是做一個整理和複習:發現原來io流是裝飾器模式:具體如下 程式IO的關鍵在於建立BufferedReader物件br:     BufferedReader br = new BufferedReader(new FileReader("file.txt"

Java 裝飾模式詳解

前言 在上面的幾篇文章中,著重介紹了java 中常見的 IO 相關知識,在學習的過程中,發現 IO 包中是用了大量的裝飾器模式,為了徹底的學習 IO,今天就來揭開裝飾器模式的面紗。 為了弄明白裝飾器模式的本質,我查看了很多資料,發現有很多文章要麼說的很苦澀,要麼舉的例

java設計模式裝飾模式

rac 都在 通過 div 過濾 一個人 創建 展開 out 裝飾器模式 裝飾器模式(Decorator Pattern)允許向一個現有的對象添加新的功能,同時又不改變其結構。 這種類型的設計模式屬於結構型模式,它是作為現有的類的一個包裝。 這種模式創建了一個裝飾類,用來包

java設計模式裝飾模式

食物 implement super map 結束 同時 ring 接口 包裝 適AT java設計模式之 裝飾器模式 裝飾器模式 裝飾器模式(Decorator Pattern)允許向一個現有的對象添加新的功能,同時又不改變其結構。 這種類型的設計模式

java裝飾模式

args pattern lte auto eight pro 簡單的 add con Decorator Pattern(裝飾器模式),定義:Attach additional responsibilities to an object dynamically. Deco

Java設計模式(9)----------裝飾模式

tor 畫框 imp 橋接 好的 找到 strac 想是 bstr 1、介紹 裝飾器模式是一種結構型的設計模式。使用該模式的目的是為了較為靈活的對類進行擴展,而且不影響原來類的結構。有同學說可以通過繼承的方式進行實現啊,沒錯,繼承的確可以實現,但是繼承的成本相對比較高,

Java進階篇設計模式之五-----外觀模式裝飾模式

和我 logs 適配器模式 del xtra implement () 實例化 網絡遊戲 前言 在上一篇中我們學習了結構型模式的適配器模式和橋接模式。本篇則來學習下結構型模式的外觀模式和裝飾器模式。 外觀模式 簡介 外觀模式隱藏系統的復雜性,並向客戶端提供了一個客戶端可以

java設計模式4.介面卡模式裝飾模式

介面卡模式 把一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法在一起工作的兩個類能夠工作。 1. 類的介面卡模式 目標角色:期望的介面,對於類的介面卡模式,此角色不可以是具體類。 源角色:需要適配的介面。 介面卡角色:把源介面轉換成目標介面,此角色必須是具

重走Java設計模式——裝飾模式(Decorator Pattern)

裝飾器模式 定義 裝飾器模式(Decorator Pattern)允許向一個現有的物件新增新的功能,同時又不改變其結構。這種型別的設計模式屬於結構型模式,它是作為現有的類的一個包裝。 這種模式建立了一個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外

Java設計模式從精通到入門二 裝飾模式

介紹 ​ 我儘量用最少的語言解釋總結: ​ Java23種設計模式之一,屬於結構型模式,允許向一個現有的物件新增新的功能,不改變其結構。 應用例項: ​ 給英雄聯盟種的射手,新增不同的裝備。先裝備攻速鞋,在裝備電刀,最後裝備無盡 uml類圖如下 主要程式碼如下 ADC類: /** *

Java設計模式 - 裝飾模式

 裝飾器模式 裝飾器模式就是在不改變原來設計的同時,動態的給物件新增一些額外的功能(加強原來的功能/拓展原來物件沒有的功能)。 UML圖示 裝飾器模式中的角色 抽象元件(Component):抽象類,規定了被裝飾者需要進行修飾的方法。 具體元件(Compone

Java IO框架與介面卡模式裝飾模式

IO框架: 介面卡模式: 介面卡模式(Adapter Pattern)是作為兩個不相容的介面之間的橋樑。這種型別的設計模式屬於結構型模式,它結合了兩個獨立介面的功能。 這種模式涉及到一個單一的類,該類負責加入獨立的或不相容的介面功能。舉個真實的例子,讀卡器是作為記憶體卡和筆

設計模式裝飾模式java實現)

裝飾器模式(Decorator):結構型設計模式,為了實現類在不修改原始類的基礎上進行動態的覆蓋或者增加方法,該實現保持了跟原有類的層級關係。這種設計模式允許向一個現有的物件新增新的功能,同時又不改變其結構。算是一種非常特殊的介面卡模式。 在實際業務中,有時候我們會建立了多層子類,但如果當子

Java設計模式之外觀模式裝飾模式的設計(精選)

前言 本篇來學習下結構型模式的外觀模式和裝飾器模式。 外觀模式 簡介 外觀模式隱藏系統的複雜性,並向客戶端提供了一個客戶端可以訪問系統的介面。這種型別的設計模式屬於結構型模式,它向現有的系統新增一個介面,來隱藏系統的複雜性。 簡單的來說就是對外提供一個簡單介面,

Java設計模式12:裝飾模式

裝飾器模式 裝飾器模式又稱為包裝(Wrapper)模式。裝飾器模式以多客戶端透明的方式擴充套件物件的功能,是繼承關係的一個替代方案。 裝飾器模式的結構 通常給物件新增功能,要麼直接修改物件新增相應的功能,要麼派生子類來擴充套件,抑或是使用物件組合的方式。顯然,直接修

Java裝飾模式

本文主要是介紹《【C++】裝飾器模式》(點選開啟連結)的Java版。關於什麼是裝飾器模式就不再贅述了,這次主要說明從UML類圖是如何與程式碼聯絡起來的。 還是從2012年上半年軟體設計師的軟考題來說明這個例子。 題目是這樣的:某咖啡店當賣咖啡時,可以根據顧客的要求在其中加入

java模式設計之裝飾模式

裝飾器模式:     使用分層物件來動態透明的向單個物件中新增責任(功能)。     裝飾器指定包裝在最初的物件周圍的所有物件都具有相同的基本介面。     某些物件是可裝飾的,可以通過將其他類包裝在這個可裝飾物件的四周,來將功能分層。     裝飾器必須具有和他所裝飾

Java設計模式裝飾模式

rgs println 應用 author nbsp bsp code 接口 main 1.裝飾器模式的定義(保持接口,擴展功能)   Decorate裝飾器,顧名思義,就是動態的給一個對象添加一些額外的職責,就好比對房子進行裝修一樣。 2.裝飾器模式的特征   具有

深入探索Java設計模式(三)之裝飾模式

裝飾器模式使你可以在執行時使用類似於物件組成的技術來裝飾類。這在我們希望例項化具有新職責的物件而無需對基礎類進行任何程式碼更改的情況下尤其有用。本文是在學習完優銳課JAVA架構VIP課程—【框架原始碼專題】中《學習原始碼中的優秀設計模式》後寫下的學習感悟。探討了這種模式,並向你展示瞭如何使用提供的Java程式