BufferedReader.close()引起的對裝飾者模式的思考

提出問題

今天在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就已經被關閉了,因此只要關閉最外層的流就能夠了,這裏用了一個裝飾者模式

相關文章
相關標籤/搜索