Java IO包中的设计模式详解

Java IO包(java.io)是设计模式应用的经典案例,其核心类库通过多种设计模式解决了“不同数据源/数据类型的读写”“功能扩展”“资源管理”等核心问题。下面我会逐一拆解IO包中用到的核心设计模式,结合源码示例和使用场景讲清楚每个模式的应用方式。

一、装饰器模式(Decorator Pattern)

核心作用

动态地给一个对象添加额外的功能,且不改变其原有结构,是继承的灵活替代方案。

IO包中的应用场景

IO包中字节流/字符流的功能扩展完全基于装饰器模式实现:

  • 抽象组件(Component)InputStream/OutputStream(字节流)、Reader/Writer(字符流)——定义了IO操作的核心接口;
  • 具体组件(ConcreteComponent)FileInputStream/FileOutputStreamFileReader/FileWriter——基础的数据源实现(直接操作文件);
  • 装饰器抽象类(Decorator)FilterInputStream/FilterOutputStreamFilterReader/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包中主要用简单工厂(静态工厂),核心体现:

  1. FileChannel的创建:FileInputStream.getChannel()FileOutputStream.getChannel()
  2. Files工具类(NIO):Files.newBufferedReader()Files.newBufferedWriter()
  3. InputStream的子类创建:FileInputStreamByteArrayInputStream等通过构造器(简化版工厂)创建。

代码示例

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/WriterInputStream/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);
        }
    }
}

总结

  1. 核心模式:Java IO包最核心的是装饰器模式(流的功能扩展)和适配器模式(字节/字符流适配),几乎所有流操作都基于这两个模式;
  2. 辅助模式:工厂模式(对象创建)、模板方法模式(算法骨架)、单例模式(标准流)是补充,解决对象创建、算法复用、全局实例问题;
  3. 设计思想:所有模式都围绕“解耦”“复用”“开闭原则”设计,比如装饰器模式让流功能可灵活组合,模板方法让算法骨架统一且子类可定制。
posted @ 2026-03-07 12:03  七星6609  阅读(0)  评论(0)    收藏  举报