裝飾器模式
抽象構件角色:給出一個抽象接口,以規范准備接受附加責任的對象。
具體構件角色:定義准備接受附加責任的對象。
抽象裝飾角色:持有一個構件對象的實例,並對應一個與抽象構件接口一致的接口。
具體裝飾角色:負責給具體構件加上額外的責任。
什么時候使用:
1. 需要擴展一個類的功能,或者給一個類增加附加責任。
2. 需要動態的給一個對象增加功能,這些功能可以再動態的撤銷。
3. 需要增加由一些基本功能的排列組合而產生的的大量的功能,從而使繼承關系變得不現實。
我以給汽車換顏色為例:
汽車廠生產汽車實例,4S店可以噴漆換顏色。
Car接口:
/** * Created by 001977 on 2019-04-12 11:39. * 抽象構件角色 */ public interface Car { /** * 出廠車身顏色 */ void skin(); }
具體構件卡羅拉:
/** * Created by 001977 on 2019-04-12 11:42. * 具體構件:COROLLA卡羅拉(灰色) */ public class Corolla implements Car { @Override public void skin() { System.out.println("超級無敵灰色"); } }
4S店抽象裝飾器:
/** * Created by 001977 on 2019-04-12 11:45. * 抽象裝飾角色(4S店) */ public abstract class FourS implements Car { private Car car; public FourS(Car car) { this.car = car; } @Override public void skin() { car.skin(); } }
具體裝飾器:噴槍紅
/** * Created by 001977 on 2019-04-12 11:49. * 具體裝飾角色(紅色噴漆) */ public class RedSprayPaint extends FourS { public RedSprayPaint(Car car) { super(car); } @Override public void skin() { super.skin(); System.out.println("花2000塊錢噴紅色的漆"); } }
具體裝飾器:噴槍白
/** * Created by 001977 on 2019-04-12 11:49. * 具體裝飾角色(白色噴漆) */ public class WhiteSprayPaint extends FourS { public WhiteSprayPaint(Car car) { super(car); } @Override public void skin() { super.skin(); System.out.println("花1000塊錢噴白色的漆"); } }
測試運行:
public class Main { public static void main(String[] args) throws IOException { System.out.println("====================出廠顏色===================="); Car corolla = new Corolla(); corolla.skin(); System.out.println("====================換顏色===================="); RedSprayPaint red = new RedSprayPaint(new WhiteSprayPaint(corolla)); red.skin(); } }
IO中的體現(以InputStream為例)
抽象構件角色:由InputStream扮演,這個抽象類為各種子類型流處理器提供統一的接口。
具體構件角色:由FileInputStream、ObjectInputStream 、ByteArrayInputStream 等原始流處理器扮演,他們實現了InputStream的接口,可以被裝飾器裝飾。
抽象裝飾角色:由FilterInputStream扮演,他也實現了InputStream的接口。
具體裝飾角色:由DataInputStream 、BufferedInputStream等扮演。
..
由於IO庫中需要很多性能的各種組合,如果用繼承方法實現,那么每一種組合都需要一個類,這樣會造成大量性能重復的類出現。如果使用裝飾器模式,那么類的數目大大減少,性能的重復也減到最少。因此裝飾器模式是IO中的基本模式。
以InputStream【抽象構件】為例:上圖中的流可以分為兩類:原始流處理器【具體構件】(FileInputStream及其左邊的類)和鏈接流處理器【裝飾器】(實現FilterInputStream的類【具體裝飾器】)。
首先InputStream定義了一些規范:
接着比如FileInputStream去實現,實際上它都是去調用本地方法的,請看:
然后裝飾器也去實現InputStream的方法,關鍵是持有InputStream對象的實例
最后具體的裝飾器比如:
BufferedInputStream裝飾了InputStream的內部工作方式,使得流的讀入操作使用緩沖機制,不會對每一次流讀入的操作都產生一次物理讀盤動作,從而提高了程序的效率。它的內部有個buf字節數組用來緩存數據。
讀取的時候調用fill方法,簡單來說就是先嘗試獲取緩沖區,然后再操作輸入流將數據讀入緩沖區,這期間還有一些細節比如調整pos不再贅述。
還有DataInputStream提供了一些直接讀取某種類型的數據的方法,省的我們讀取完再去做轉換。
比如:readBoolean
它的讀入操作read方法就是直接調用原始流處理器的方法,並不復雜
最后附上一張畫了一天的IO繼承關系圖:
如果圖片看不清,鼠標右鍵---在新標簽頁下打開圖片