Decorator裝飾器,就是動態地給一個對象添加一些額外的職責,動態擴展,和下面繼承(靜態擴展)的比較。所以,裝飾器模式具備以下的特徵:html
總結:保持接口,動態加強性能。java
裝飾器經過包裝一個裝飾對象來擴展其功能,而又不改變其接口,這其實是基於對象的適配器模式的一種變種。與對象的適配器模式異同:設計模式
適配器模式是在適配器中,重寫舊接口的方法來調用新接口方法,來實現舊接口不改變,同時使用新接口的目的。新接口適配舊接口。數組
而裝飾模式,是裝飾器和舊接口實現相同的接口,在調用新接口的方法中,會調用舊接口的方法,並對其進行擴展。
app
功能的拓展,一般可使用繼承的方式解決。但這樣實現的話,每一種組合都須要一個類,大量重複性內容,類數目「爆炸」;另外,這些拓展的功能必需要是能夠預見,編譯時就肯定了,靜態的擴展。socket
一個例子大概說:Beverage是一個抽象類,它被全部在一個咖啡店裏賣的飲料繼承。Beverage有個抽象方法cost,全部的子類都要實現這個抽象方法,計算它們的價格。如今有四個最基本的咖啡:HouseBlend,DarkRoast,Decaf,Espresso他們都繼承自Beverage,如今的需求是說在四個最基本的咖啡裏,每一個均可以隨便地添加調味品,像steamed milk,soy,還有mocha最後是加上whipped milk。若是是說按繼承來實現這種幾個調味品跟原來咖啡的組合的話,咱們會很天然地設計來下面的類圖來:
ide
若是是按裝飾模式的設計思路咱們能夠得出下面的設計類圖:
性能
裝飾模式是怎麼達到不只類的數目大減小了,性能的重複也能夠減至到最少。this
一句話解釋:裝飾者和被裝飾者須要繼承同一個接口或者是抽象類,被裝飾者做爲裝飾者的一個變量。程序中原來調用被裝飾者某方法func1的地方改爲調用裝飾者相同的那個方法func1,而且裝飾者的該方法func1上添加了一些額外的功能,在方法func1中再調用被裝飾着的方法func1。
這就是動態的擴展。.net
目的:將一個類的接口轉換成客戶指望的另外一個接口,讓本來不兼容的接口能夠合做無間。
我國國標充電器三孔,德國得標充電器兩孔。現去德國旅行。如何將咱們的三孔充電器插入兩孔。這就須要適配器。
類圖:
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》
因爲java I/O庫須要不少性能的各類組合,若是這些性能都是用繼承來實現,那麼每一種組合都須要一個類,大量重複類。
首先,須要理解java I/O庫是由一些原始流處理器和圍繞它的裝飾流處理器(裝飾器,動態擴展原始類性能)所組成的。
這裏以InputStream爲例,並附上結構圖。
這些流類分紅兩種,即原始流類(Original Stream)和連接流處理器(Wrapper Stream)。
原始流處理器接收一個Byte數組對象,String對象,FileDiscriptor對象或者不一樣類型的流源對象,原始流處理器包括如下四種:
所謂連接流處理器,就是能夠接收另外一個流對象做爲源,並對之進行功能擴展的類。InputStream類型的連接處理接收另外一個InputStream對象做爲流源。
以FilterInputStream過濾輸入流的子類爲例。它將另外一個輸入流做爲流源。這個類的子類包括如下幾種:
原始流,就是裝模式中具體構件角色(被裝飾者),連接流,就是裝飾模式中的裝飾角色。
一句話總結:連接流處理器,接收原始流處理器並將其做爲成員變量引用,都繼承了相同的抽象類InputStream。他們在內部工做方法中作了相應改變,在連接流的相同方法中擴展原始流中的方法,這種變化就是裝飾模式的目的。
StringBufferInputStream是一個適配器類,其繼承了InputStream類型,同時持有一個對String類型的引用。這是將處理String對象的新接口適配成InputStream的舊接口的適配器模式。
其他OutputStream、Reader和Writer的裝飾模式和適配器模式 參考《http://www.cnblogs.com/wxgblogs/p/5649933.html》 和《http://www.cnblogs.com/heartstage/p/3391070.html》