Java IO包中的设计模式详解
Java IO包(java.io)是设计模式应用的经典案例,其核心类库通过多种设计模式解决了“不同数据源/数据类型的读写”“功能扩展”“资源管理”等核心问题。下面我会逐一拆解IO包中用到的核心设计模式,结合源码示例和使用场景讲清楚每个模式的应用方式。
一、装饰器模式(Decorator Pattern)
核心作用
动态地给一个对象添加额外的功能,且不改变其原有结构,是继承的灵活替代方案。
IO包中的应用场景
IO包中字节流/字符流的功能扩展完全基于装饰器模式实现:
- 抽象组件(Component):
InputStream/OutputStream(字节流)、Reader/Writer(字符流)——定义了IO操作的核心接口; - 具体组件(ConcreteComponent):
FileInputStream/FileOutputStream、FileReader/FileWriter——基础的数据源实现(直接操作文件); - 装饰器抽象类(Decorator):
FilterInputStream/FilterOutputStream、FilterReader/FilterWriter——继承自核心组件,持有一个核心组件的引用; - 具体装饰器(ConcreteDecorator):
BufferedInputStream(缓冲)、DataInputStream(基本类型读写)、InputStreamReader(字节转字符)——给基础流添加额外功能。
代码示例(装饰器模式核心体现)
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class DecoratorPatternDemo {
public static void main(String[] args) {
// 1. 基础组件:FileInputStream(直接读文件,无缓冲)
try (InputStream fileIn = new FileInputStream("test.txt");
// 2. 装饰器:BufferedInputStream(给基础流添加缓冲功能)
InputStream bufferedIn = new BufferedInputStream(fileIn);
// 可叠加多个装饰器:比如再套DataInputStream(添加基本类型读写)
// DataInputStream dataIn = new DataInputStream(bufferedIn);
) {
int data;
// 缓冲流通过预读数据减少磁盘IO,功能扩展但不改变InputStream接口
while ((data = bufferedIn.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
关键特点
- 装饰器和被装饰者实现同一个接口(如都继承
InputStream),对外暴露统一API; - 可叠加多个装饰器(如
BufferedInputStream + DataInputStream),灵活组合功能; - 无需修改原有类代码,符合“开闭原则”。
二、适配器模式(Adapter Pattern)
核心作用
将一个类的接口转换成客户期望的另一个接口,解决接口不兼容的问题。
IO包中的应用场景
最典型的是字节流与字符流的适配:
- 字节流(
InputStream/OutputStream):处理二进制数据; - 字符流(
Reader/Writer):处理文本数据(按字符编码); - 适配器类:
InputStreamReader(字节流→字符流)、OutputStreamWriter(字节流→字符流)。
源码核心逻辑(InputStreamReader)
// InputStreamReader 实现了 Reader(字符流接口),内部持有 InputStream(字节流)和编码转换器
public class InputStreamReader extends Reader {
private final StreamDecoder sd; // 核心适配器:将字节解码为字符
// 构造器:传入字节流(被适配者),适配为字符流
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
// 重写Reader的read方法,底层调用字节流的读取+解码
public int read() throws IOException {
return sd.read();
}
}
使用示例
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
public class AdapterPatternDemo {
public static void main(String[] args) {
// 字节流(FileInputStream)是被适配者
try (FileInputStream fis = new FileInputStream("test.txt");
// 适配器:将字节流适配为字符流(Reader)
Reader reader = new InputStreamReader(fis, "UTF-8")) {
int ch;
// 按字符读取(适配后的接口)
while ((ch = reader.read()) != -1) {
System.out.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、工厂模式(Factory Pattern)
核心作用
隐藏对象创建的细节,通过统一接口创建对象,降低耦合。
IO包中的应用场景
IO包中主要用简单工厂(静态工厂),核心体现:
FileChannel的创建:FileInputStream.getChannel()、FileOutputStream.getChannel();Files工具类(NIO):Files.newBufferedReader()、Files.newBufferedWriter();InputStream的子类创建:FileInputStream、ByteArrayInputStream等通过构造器(简化版工厂)创建。
代码示例
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class FactoryPatternDemo {
public static void main(String[] args) {
// 静态工厂方法:Files.newBufferedReader(创建BufferedReader对象,隐藏创建细节)
try (BufferedReader br = Files.newBufferedReader(Paths.get("test.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
// FileChannel的工厂方法(实例工厂)
try (FileInputStream fis = new FileInputStream("test.txt")) {
// getChannel() 是工厂方法,创建FileChannel实例
System.out.println(fis.getChannel().size());
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、单例模式(Singleton Pattern)
核心作用
保证一个类只有一个实例,并提供全局访问点。
IO包中的应用场景
java.io.FileDescriptor中的标准流实例(stdin/stdout/stderr)是单例:
public final class FileDescriptor {
// 静态单例:标准输入、输出、错误流
public static final FileDescriptor in = new FileDescriptor(0);
public static final FileDescriptor out = new FileDescriptor(1);
public static final FileDescriptor err = new FileDescriptor(2);
private FileDescriptor(int fd) {
this.fd = fd;
this.handle = new Handle(fd);
}
// 其他代码...
}
使用场景
System.in/System.out底层依赖这些单例:
// System.out 底层是 PrintStream,关联 FileDescriptor.out 单例
System.out.println("Hello IO");
// System.in 关联 FileDescriptor.in 单例
System.in.read();
五、模板方法模式(Template Method Pattern)
核心作用
定义一个算法的骨架,将步骤延迟到子类实现,保证算法结构不变。
IO包中的应用场景
Reader/Writer、InputStream/OutputStream的抽象类定义了核心方法的骨架,子类实现具体逻辑:
- 抽象类(模板):
InputStream定义了read()(单字节读取)、read(byte[])(批量读取)的骨架; - 子类(实现):
FileInputStream重写read()方法,实现从文件读取字节的具体逻辑。
源码核心逻辑(InputStream)
public abstract class InputStream implements Closeable {
// 抽象方法(子类必须实现):核心步骤延迟到子类
public abstract int read() throws IOException;
// 模板方法:定义批量读取的算法骨架,复用逻辑
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
// 模板方法:批量读取的具体骨架
public int read(byte b[], int off, int len) throws IOException {
// 校验逻辑(固定)
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
// 调用抽象方法read()(子类实现)
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
// 循环读取(固定逻辑)
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
}
子类实现(FileInputStream)
public class FileInputStream extends InputStream {
// 实现抽象方法read():具体的文件读取逻辑
public int read() throws IOException {
return read0(); // 本地方法,实现从文件读取单字节
}
// 可选重写批量读取(优化性能)
public int read(byte b[], int off, int len) throws IOException {
return readBytes(b, off, len); // 优化后的批量读取
}
}
六、观察者模式(Observer Pattern)
核心作用
对象间一对多的依赖,当一个对象状态变化,所有依赖者都会收到通知。
IO包中的应用场景
java.io.Observer(已标记为过时,但仍是经典应用)和Observable类:
- 比如监控文件变化时,可通过
Observable包装文件流,状态变化时通知观察者。
简化示例
import java.io.File;
import java.io.IOException;
import java.util.Observable;
import java.util.Observer;
// 被观察者:监控文件变化
class FileObservable extends Observable {
private File file;
private long lastModified;
public FileObservable(File file) {
this.file = file;
this.lastModified = file.lastModified();
}
public void checkChange() {
long current = file.lastModified();
if (current != lastModified) {
lastModified = current;
setChanged(); // 标记状态变化
notifyObservers(file); // 通知观察者
}
}
}
// 观察者:处理文件变化
class FileObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
File file = (File) arg;
System.out.println("文件 " + file.getName() + " 已修改");
}
}
public class ObserverPatternDemo {
public static void main(String[] args) throws IOException, InterruptedException {
File file = new File("test.txt");
FileObservable observable = new FileObservable(file);
observable.addObserver(new FileObserver());
// 模拟监控文件变化
while (true) {
observable.checkChange();
Thread.sleep(1000);
}
}
}
总结
- 核心模式:Java IO包最核心的是装饰器模式(流的功能扩展)和适配器模式(字节/字符流适配),几乎所有流操作都基于这两个模式;
- 辅助模式:工厂模式(对象创建)、模板方法模式(算法骨架)、单例模式(标准流)是补充,解决对象创建、算法复用、全局实例问题;
- 设计思想:所有模式都围绕“解耦”“复用”“开闭原则”设计,比如装饰器模式让流功能可灵活组合,模板方法让算法骨架统一且子类可定制。
百流积聚,江河是也;文若化风,可以砾石。

浙公网安备 33010602011771号