今天在coding的時候發現了個問題,使用流的時候,處理流會包裝一個節點流,可是在流關閉的時候,咱們只須要關閉處理流(最外層的流),被包裝的節點流都不關閉,這是怎麼回事呢,咱們以FileReader 和BufferedReader爲例子java
package src.main.java.com.Io; import java.io.BufferedReader; import java.io.FileReader; /** * 字符方式 * BufferedReader 帶有緩衝區的 字符輸入流 * BufferedWriter 帶有緩衝區的 字符輸出流 * * @author liuhuxiang * @version $Id: BufferedReaderTest01.java, v 0.1 2018年06月01日 15:03 liuhuxiang Exp $ * 關閉最外層的包裝便可(裝飾者模式) * readLine() 方法,一讀讀一行 * 這裏爲了簡單些,異常直接拋出,沒有處理 */ public class BufferedReaderTest01 { public static void main(String[] args) throws Exception { String path = "D:\\work\\BufferedReaderTest01.java"; BufferedReader bufferedReader = new BufferedReader(new FileReader(path)); //根據流出現的位置 節點流/處理流 //FileReader 節點流,就是一個節點,被別人包裝的 //BufferedReader 處理流/節點流 String temp=null; while((temp=bufferedReader.readLine())!=null){ System.out.println(temp); } // 這裏注意,要關閉,只要關閉最外層的包裝流便可,這裏涉及一個裝飾者模式 bufferedReader.close(); } }
上面代碼咱們發現,只關閉了緩衝字符輸入流,可是沒有關閉文件字符流this
咱們先不着急去解決這個問題,先提另一個問題spa
A類中有m1方法 ,我想對m1方法進行擴展,怎麼辦?對象
小夥伴必定會迅速寫出代碼,繼承,用多態的特性,直接上代碼了繼承
package src.main.java.com.Io.decker; public class A { public void m1() { System.out.println("A--aMethod"); } }
package src.main.java.com.Io.decker; public class B extends A{ public void m1(){ System.out.println("b---bMethod1"); super.m1(); System.out.println("b---bMethod2"); } }
package src.main.java.com.Io.decker; public class Test01 { public static void main(String[] args) { // 父類的引用指向子類的對象,換句話說,此時,B可以拿到父類A的引用 // a只能調用到A類中的方法,可是B繼承於A,發生重寫的時候(方法名徹底一致的時候),會調用到B上 // 可是僅限於此,父類中其餘方法,沒有發生重寫的,子類B調用不到 A a=new B(); a.m1(); } }
console b---bMethod1 A--aMethod b---bMethod2
好了,完成了,可是這樣有個問題,耦合性太強了,A中m1修改的話,B也要修改,因此不推薦這樣寫,那怎麼辦,今天的主角登場,裝飾者模式接口
咱們就以FileReader Bufferedreader爲例子it
package src.main.java.com.Io.decker; /** * 被裝飾者 */ public class FileReader { public void close(){ System.out.println("FileReader----close"); } }
package src.main.java.com.Io.decker; /** * BufferedReader.close(),就不須要FileReader.close()(只須要關閉最外層的流) * 裝飾者 */ public class Bufferedreader { private FileReader fileReader; Bufferedreader(FileReader fileReader) { this.fileReader = fileReader; } public void close(){ System.out.println("----------擴展代碼1--------"); fileReader.close(); System.out.println("----------擴展代碼2--------"); } }
這裏是吧FileReader做爲成員變量(兄弟關係),而不是像上面的例子同樣,經過繼承(父子關係)io
這樣的話,即使FileReader裏面有改動,仍然不影響Bufferedreaderconsole
package src.main.java.com.Io.decker; /** */ public class Test02 { public static void main(String[] args) { //建立裝飾者 FileReader fr = new FileReader(); //建立被裝飾者 Bufferedreader bf = new Bufferedreader(fr); //執行完成咱們發現,對FileReader進行了擴展 bf.close(); } }
console ----------擴展代碼1-------- FileReader----close ----------擴展代碼2--------
1 裝飾者中必需要包含被裝飾者class
2 裝飾者模式的要求,裝飾者和被裝飾者必需要實現同一個接口或者類型
如上面的例子,都有close(),那麼咱們對代碼進行改造下,提出一個抽象方法,被裝飾者和裝飾者分別繼承
public abstract class Reader { public abstract void close(); }
public class FileReader extends Reader {
public void close(){
System.out.println("FileReader----close");
}
}
public class Bufferedreader extends Reader{ private Reader reader; Bufferedreader(Reader reader) { // 這裏是個多態 Reader reader=new FileReader(); this.reader = reader; } public void close(){ System.out.println("----------擴展代碼1--------"); reader.close(); System.out.println("----------擴展代碼2--------"); } }
這樣的話就知足了裝飾者模式的要求,並且Bufferedreader和FileReader 的關係就不大了,由於在Bufferedreader裏面,成員變量不是一個具體的類型,是一個抽象類
public class Test02 { public static void main(String[] args) { FileReader fr = new FileReader(); Bufferedreader bf = new Bufferedreader(fr); bf.close(); } }
這是後咱們發現,原來在關閉BufferedReader的時候,FileReader就已經被關閉了,因此只要關閉最外層的流就能夠了,這裏用了一個裝飾者模式