什么是节点流和处理流
在[Java文件操作(二)——浅谈Java中I/O(上)](http://blog.csdn.net/qq_24789865/article/details/48835713)中,我把Java中的IO分类为两大类,第一种是字节流,第二种是字符流。这是根据它们在处理数据时的方式不同来分类的(字节流处理数据以字节为基础,字符流以字符为基础),在这里我们换一个角度,以功能不同来对Java中的IO进行分类。
根据功能的不同,我们又可以把Java中的IO分为:
1.节点流
2.处理流
所谓节点流呢,你可以想象它是一根真实的管道,它里面流淌着真实的数据(具体实现了对数据的读或写),而处理流呢,就是在节点流这根管道上新增了一些功能,它可以对节点流中的数据进行进一步的处理。可能这种说法比较抽象,下面我们就通过代码来看一下Java中的处理流是怎样的
在这之前,先说一下今天用到的一个处理流BufferedReader
当你看到它的第一眼,你应该就知道,它首先是一个字符输入流(以“Reader”结尾),然后它是一个处理流,所以它又叫做“字符输入处理流”,他有一个核心方法:
public String readLine();
即一次读取一行数据,返回值为null时,代表数据读取结束
示例代码:
import java.io.*;
public class Test{
public static void main(String args[]){
FileReader fr = null;
BufferedReader bfr = null;
try{
fr = new FileReader("F:/from.txt");
bfr = new BufferedReader(fr);
String line = null;
while(true){
line = bfr.readLine();
if(line == null){
break;
}
System.out.println(line);
}
}
catch(Exception e){
System.out.println(e);
}
}
}
BufferedReader在创建对象的时候,是将FileReader的对象作为参数传递给了BufferedReader的对象。在进行数据处理的时候,真正实现数据读取的功能是FileReader的对象,而BufferedReader是对FileReader所读取的数据在readLine()中进行进一步处理,进而实现了一次读取一行的功能。其实这整个过程就是一个典型的“工厂模式”的实现(也叫做“装饰者模式”)
工厂模式(装饰者模式)
下面我们就通过另外一个例子来,来帮助大家进一步理解“工厂模式”的思想:
![](https://img-blog.csdn.net/20151003164521396)
上图中,【员工】是对所有不同工种的员工的一个抽象,具体实现【员工】的可以是一个水管工,可以是一个木匠,可以是一个电工等,这样,就有很多个不同的工种。但是不能是什么工种的员工,他们终将属于某一家公司,无论是A公司,B公司,C公司......,那么问题来了,如果有m个工种,n家公司,并且每家公司都有m个工种,按照传统的继承体系就要写m*n个员工类(A公司水管,B公司水管工,C公司水管工......),这显然是相当繁冗的,那么我们可不可以通过一个什么方法,我们不用把所有的公司的所有员工的类都一一写出来,而是当公司需要一个什么样员工的时候,就生成一个什么样的员工,这样一来,事情就变得非常简洁了。嗯,没错,这就是“工厂模式”的核心思想:需要的时候再创建。
下面我们通过代码来具体实现上面的案例:
(1)首先,创建一个Worker接口,它代表了所有员工的抽象:
interface Worker{
public void doSomeWork();
}
(2)分别创建Plumbe类和Carpenter类,他们具体是实现【水管工】 和【木匠】,它们都是Worker的子类:
Plumbe类:
public class Plumber implements Worker{
public void doSomeWork(){
System.out.println("修水管");
}
}
水管工要做的事就是“修水管”,所以重写方法中打印“修水管”。
Carpenter类:
public class Carpenter implements Worker{
public void doSomeWork(){
System.out.println("修门窗");
}
}
木匠要做的事就是“修门窗”,所以重写方法中打印“修门窗”
(3)创建AWorker类和BWorker类,它们分别代表了A公司员工的抽象和B公司所有员工的抽象,它们都是Worker的子类:
AWorker类:
public class AWorker implements Worker{
private Worker worker;
public AWorker(Worker worker){
this.worker = worker;
}
public void doSomeWork(){
System.out.println("你好!");
worker.doSomeWork();
}
}
BWorker类:
public class BWork() implements Worker{
private Worker worker;
public BWorker(Worker worker){
this.worker = worker;
}
public void doSomeWork(){
System.out.println("穿鞋套!");
worker.doSomeWork();
}
}
细心的读者可能注意到了,在这两个类中,都有声明一个Worker的引用。那么,它在这里有什么用呢?
哈哈哈哈,其实这就是今天我要说的“工厂模式”的思想的精髓所在。。。。
【A公司员工】类(Aworker)的内部的有一个【员工引用】(private Worker worker),实际上这个引用就代表了一个员工,这个员工可能是【水管工】(Plumbe),可能是【木匠】(Carpenter)等,在A公司没有这个工种的时候,它是不确定的。当A公司需要一个工种(比如【水管工】)的时候,就直接把【水管工】这个类的对象作为参数赋值给这个【员工引用】,此时此刻,【员工引用】就代表了一个水管工,这个【A公司员工】就变成了一个【A公司水管工】,同理,如果传递的是【木匠】这个类的对象,这个【A公司员工】就变成了一个【A公司木匠】......
(3)写一个测试类:
class Test{
public static void main(String args[]){
Plumber p = new Plumber();
AWorker a = new AWorker(p);
a.doSomeWork();
}
运行结果:
你好!
修水管
在这个过程中【A公司员工】是一个“装饰者”,【水管工】是一个“被装饰者”,【水管工】最初能做的事只有“修水管”,但是在通过【A公司员工】进行装饰过后,他就会在“修水管”之前先说“你好”。
总结
在了解的工厂模式的思想后,再回到代码中,我们就知道了FileReader相当于“【水管工】”,是一个“被装饰者”,它真正实现了对数据的读取,而BufferedReader相当于“【A公司员工】”,是一个“装饰者”,它用来“装饰”FileReader,在FileReader所拥有的功能的基础上,新增了一次读取一行的功能。此外,BufferedReader作为一个“装饰者”,它不仅仅可以装饰FileReader,只要是Reader的子类它都可以装饰。
所以,在Java中节点流和处理流之间,节点流就是“被装饰者”,处理流就是“装饰着”,节点流在被处理流“装饰”后,就可以在节点流原有功能的基础上,实现一些新的功能。