Java--23种设计模式之decorator模式
裝飾模式:裝飾模式以對客戶端透明的方式擴展對象的功能,是繼承關(guān)系的一個替代方案,提供比繼承更多的靈活性。動態(tài)給一個對象增加功能,這些功能可以再動態(tài)的撤消。增加由一些基本功能的排列組合而產(chǎn)生的非常大量的功能。是在不必改變原類文件和不使用繼承的情況下,動態(tài)的擴展一個對象的功能。它是通過創(chuàng)建一個包裝對象,也就是裝飾來包裹真實的對象
趣味解釋:DECORATOR—Mary過完輪到Sarly過生日,還是不要叫她自己挑了,不然這個月伙食費肯定玩完,拿出我去年在華山頂上照的照片,在背面寫上“最好的的禮物,就是愛你的Fita”,再到街上禮品店買了個像框(賣禮品的MM也很漂亮哦),再找隔壁搞美術(shù)設(shè)計的Mike設(shè)計了一個漂亮的盒子裝起來……,我們都是Decorator,最終都在修飾我這個人呀,怎么樣,看懂了嗎?趣味解釋參見:http://blog.jobbole.com/20496/
Java代碼中實現(xiàn):以Java中的輸入輸出流為例,Java中的處理流即是對節(jié)點流的包裝和裝飾
package decorator;import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.PushbackInputStream; import java.io.PushbackReader;public class IOTest {/* test.txt內(nèi)容:* hello world!*/public static void main(String[] args) throws IOException, ClassNotFoundException {//文件路徑可自行更換final String filePath = "F:/eclipse/workspace/decorator/Test.txt";//InputStream相當于被裝飾的接口或者抽象類,FileInputStream相當于原始的待裝飾的對象,FileInputStream無法裝飾InputStream//另外FileInputStream是以只讀方式打開了一個文件,并打開了一個文件的句柄存放在FileDescriptor對象的handle屬性//所以下面有關(guān)回退和重新標記等操作,都是在堆中建立緩沖區(qū)所造成的假象,并不是真正的文件流在回退或者重新標記InputStream inputStream = new FileInputStream(filePath);final int len = inputStream.available();//記錄一下流的長度System.out.println("FileInputStream不支持mark和reset:" + inputStream.markSupported());System.out.println("---------------------------------------------------------------------------------");/* 下面分別展示三種裝飾器的作用BufferedInputStream,DataInputStream,PushbackInputStream,LZ下面做了三個裝飾器的功能演示 *///首先裝飾成BufferedInputStream,它提供我們mark,reset的功能BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);//裝飾成 BufferedInputStreamSystem.out.println("BufferedInputStream支持mark和reset:" + bufferedInputStream.markSupported());bufferedInputStream.mark(0);//標記一下char c = (char) bufferedInputStream.read();System.out.println("Test.txt文件的第一個字符:" + c);bufferedInputStream.reset();//重置c = (char) bufferedInputStream.read();//再讀System.out.println("重置以后再讀一個字符,依然會是第一個字符:" + c);bufferedInputStream.reset();System.out.println("---------------------------------------------------------------------------------");//裝飾成 DataInputStream,我們?yōu)榱擞质褂肈ataInputStream,又使用BufferedInputStream的mark reset功能,所以我們再進行一層包裝//注意,這里如果不使用BufferedInputStream,而使用原始的InputStream,read方法返回的結(jié)果會是-1,即已經(jīng)讀取結(jié)束//因為BufferedInputStream已經(jīng)將文本的內(nèi)容讀取完畢,并緩沖到堆上,默認的初始緩沖區(qū)大小是8192BDataInputStream dataInputStream = new DataInputStream(bufferedInputStream);dataInputStream.reset();//這是BufferedInputStream提供的功能,如果不在這個基礎(chǔ)上包裝會出錯System.out.println("DataInputStream現(xiàn)在具有readInt,readChar,readUTF等功能");int value = dataInputStream.readInt();//讀出來一個int,包含四個字節(jié)//我們轉(zhuǎn)換成字符依次顯示出來,可以看到LZ文件的前四個字符String binary = Integer.toBinaryString(value);int first = binary.length() % 8;System.out.print("使用readInt讀取的前四個字符:");for (int i = 0; i < 4; i++) {if (i == 0) {System.out.print(((char)Integer.valueOf(binary.substring(0, first), 2).intValue()));}else {System.out.print(((char)Integer.valueOf(binary.substring(( i - 1 ) * 8 + first, i * 8 + first), 2).intValue()));}}System.out.println();System.out.println("---------------------------------------------------------------------------------");//PushbackInputStream無法包裝BufferedInputStream支持mark reset,因為它覆蓋了reset和mark方法//因為流已經(jīng)被讀取到末尾,所以我們必須重新打開一個文件的句柄,即FileInputStreaminputStream = new FileInputStream(filePath);PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream,len);//裝飾成 PushbackInputStreamSystem.out.println("PushbackInputStream裝飾以后支持退回操作unread");byte[] bytes = new byte[len];pushbackInputStream.read(bytes);//讀完了整個流System.out.println("unread回退前的內(nèi)容:" + new String(bytes));pushbackInputStream.unread(bytes);//再退回去bytes = new byte[len];//清空byte數(shù)組pushbackInputStream.read(bytes);//再讀System.out.println("unread回退后的內(nèi)容:" + new String(bytes));System.out.println("---------------------------------------------------------------------------------");/* 以上有兩個一層裝飾和一個兩層裝飾,下面我們先裝飾成Reader,再進行其它裝飾 *///由于之前被PushbackInputStream將流讀取到末尾,我們需要再次重新打開文件句柄inputStream = new FileInputStream(filePath);InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"utf-8");//先裝飾成InputStreamReaderSystem.out.println("InputStreamReader有reader的功能,比如轉(zhuǎn)碼:" + inputStreamReader.getEncoding());System.out.println("---------------------------------------------------------------------------------");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);//我們進一步在reader的基礎(chǔ)上裝飾成BufferedReaderSystem.out.println("BufferedReader有readLine等功能:" + bufferedReader.readLine());System.out.println("---------------------------------------------------------------------------------");LineNumberReader lineNumberReader = new LineNumberReader(inputStreamReader);//我們進一步在reader的基礎(chǔ)上裝飾成LineNumberReaderSystem.out.println("LineNumberReader有設(shè)置行號,獲取行號等功能(行號從0開始),當前行號:" + lineNumberReader.getLineNumber());System.out.println("---------------------------------------------------------------------------------");//此處由于剛才被readLine方法將流讀取到末尾,所以我們再次重新打開文件句柄,并需要將inputstream再次包裝成readerinputStreamReader = new InputStreamReader(new FileInputStream(filePath));PushbackReader pushbackReader = new PushbackReader(inputStreamReader,len);//我們進一步在reader的基礎(chǔ)上裝飾成PushbackReaderSystem.out.println("PushbackReader是擁有退回操作的reader對象");char[] chars = new char[len];pushbackReader.read(chars);System.out.println("unread回退前的內(nèi)容:" + new String(chars));pushbackReader.unread(chars);//再退回去chars = new char[len];//清空char數(shù)組pushbackReader.read(chars);//再讀System.out.println("unread回退后的內(nèi)容:" + new String(chars));}}運行結(jié)果:
FileInputStream不支持mark和reset:false
---------------------------------------------------------------------------------
BufferedInputStream支持mark和reset:true
Test.txt文件的第一個字符:H
重置以后再讀一個字符,依然會是第一個字符:H
---------------------------------------------------------------------------------
DataInputStream現(xiàn)在具有readInt,readChar,readUTF等功能
使用readInt讀取的前四個字符:Hell
---------------------------------------------------------------------------------
PushbackInputStream裝飾以后支持退回操作unread
unread回退前的內(nèi)容:Hello World!
unread回退后的內(nèi)容:Hello World!
---------------------------------------------------------------------------------
InputStreamReader有reader的功能,比如轉(zhuǎn)碼:UTF8
---------------------------------------------------------------------------------
BufferedReader有readLine等功能:Hello World??
---------------------------------------------------------------------------------
LineNumberReader有設(shè)置行號,獲取行號等功能(行號從0開始),當前行號:0
---------------------------------------------------------------------------------
PushbackReader是擁有退回操作的reader對象
unread回退前的內(nèi)容:Hello World!
?上圖中畫出了輸入輸出流的類圖,和裝飾器模式對照。其中InputStreamReader轉(zhuǎn)換流比較特殊,即是InputStream輸入流裝飾產(chǎn)生,同時又是Reader字符流的裝飾原始類。
分析此圖可以看出:裝飾器模式的靈活,我們創(chuàng)建的一個FileInputstream對象,我們可以使用各種裝飾器讓它具有不同的特別的功能,這正是動態(tài)擴展一個類的功能的最佳體現(xiàn),而裝飾器模式的靈活性正是JAVA中IO所需要的,不得不贊一下JAVA類庫的建造者實在是強悍。上述的XXXXInputStream的各個類都繼承了InputStream,這樣做不僅是為了復用InputStream的父類功能(InputStream也是一種模板方法模式,它定義了read(byte[])方法的簡單算法,并將read()方法交給具體的InputStream去實現(xiàn)),也是為了可以重疊裝飾,即裝飾器也可以再次被裝飾,而過渡到Reader以后,Reader的裝飾器體系則是類似的。
總結(jié):裝飾器模式就是一個可以非常靈活的動態(tài)擴展類功能的設(shè)計模式,它采用組合的方式取代繼承,使得各個功能的擴展更加獨立和靈活。
參考文章:http://www.cnblogs.com/zuoxiaolong/p/pattern11.html
轉(zhuǎn)載于:https://www.cnblogs.com/graceting/p/4120210.html
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Java--23种设计模式之decorator模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网站自行备案流程
- 下一篇: C# random helper cla