今天在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就已经被关闭了,因此只要关闭最外层的流就能够了,这里用了一个装饰者模式