【Java教程】Day10-04 IO:Filter模式(装饰器模式)详解

在Java中,InputStreamOutputStream是进行流式输入输出的核心类,它们提供了处理字节数据的基本操作。然而,在实际开发中,我们常常需要对流进行增强,比如添加缓冲功能、加密、签名等。传统的继承方式会导致子类数量爆炸,变得难以管理。为了解决这一问题,Java采用了Filter模式(也叫装饰器模式),允许通过组合多个装饰器来扩展流的功能,而无需修改原有类。

1. 输入流(InputStream)和输出流(OutputStream)

Java的IO库提供了两种主要的流类型:InputStreamOutputStream。这两者都用于处理字节数据的读写操作。

  • InputStream:从数据源(如文件、网络、内存等)读取数据。

  • OutputStream:将数据写入目标(如文件、网络、内存等)。

 

1.1 基本的输入流

以下是几种常见的InputStream的实现类:

  • FileInputStream:从文件读取数据。

  • ServletInputStream:从HTTP请求读取数据。

  • Socket.getInputStream():从TCP连接读取数据。

 

然而,如果我们想为FileInputStream增加额外的功能(比如缓冲、签名或加密),直接使用继承方式会导致代码的复杂度急剧增加。例如,为FileInputStream添加缓冲功能,可能需要创建多个子类:

javaclass BufferedFileInputStream extends FileInputStream { ... }class DigestFileInputStream extends FileInputStream { ... }class CipherFileInputStream extends FileInputStream { ... }

 

如果需要组合这些功能(例如同时添加缓冲和加密),则需要更多的子类,例如:

javaclass BufferedDigestFileInputStream extends BufferedFileInputStream { ... }class BufferedCipherFileInputStream extends BufferedFileInputStream { ... }

 

这种方式显然会导致子类数量膨胀,难以维护。

 

 

2. 使用Filter模式(装饰器模式)

为了解决继承导致的代码复杂性,Java采用了Filter模式(又称装饰器模式)。通过这个模式,我们可以在运行时动态地为InputStreamOutputStream添加功能,而无需修改原有的类。

2.1 基本思想

Filter模式通过将一个流(如FileInputStream)“包装”成另一个流(如BufferedInputStreamGZIPInputStream),允许我们以更灵活的方式组合不同的功能。

假设我们有一个FileInputStream对象,我们希望通过以下方式来增强它:

  1. 给流添加缓冲功能,提高读取效率;

  2. 处理压缩数据,直接读取解压缩后的内容。

我们可以按如下方式嵌套多个流:

javaInputStream file = new FileInputStream("test.gz"); // 基础数据源InputStream buffered = new BufferedInputStream(file); // 添加缓冲功能InputStream gzip = new GZIPInputStream(buffered); // 解压缩功能

 

通过这种方式,我们将多个功能组合成一个流,而最终得到的对象仍然是InputStream,我们可以像使用普通InputStream一样读取数据。

2.2 Filter模式示意图

plaintext┌────────────────────────┐│     GZIPInputStream    ││┌──────────────────────┐│││BufferedFileInputStream││││┌────────────────────┐│││││   FileInputStream   │││││└────────────────────┘││└───────────────────────┘

2.3 这种模式的优势

  1. 灵活组合:我们可以动态地将多个装饰器组合在一起,以实现不同的功能,而不需要大量创建子类。

  2. 代码复用:相同的装饰器可以多次使用,提高代码复用性。

  3. 减少类爆炸:无需为每个功能的组合创建新的子类,避免类数量过多,代码更加简洁。

 

3. 自定义FilterInputStream

Java的IO库提供了FilterInputStreamFilterOutputStream作为基础类,可以方便地自定义功能。以下是一个自定义FilterInputStream的示例,我们创建一个CountInputStream类,能够统计读取的字节数:

3.1 代码示例

javaimport java.io.*;public class Main {    public static void main(String[] args) throws IOException {        byte[] data = "hello, world!".getBytes("UTF-8");        try (CountInputStream input = new CountInputStream(new ByteArrayInputStream(data))) {            int n;            while ((n = input.read()) != -1) {                System.out.println((char)n);            }            System.out.println("Total read " + input.getBytesRead() + " bytes");        }    }}class CountInputStream extends FilterInputStream {    private int count = 0;    CountInputStream(InputStream in) {        super(in);    }    public int getBytesRead() {        return this.count;    }    @Override    public int read() throws IOException {        int n = in.read();        if (n != -1) {            this.count++;        }        return n;    }    @Override    public int read(byte[] b, int off, int len) throws IOException {        int n = in.read(b, off, len);        if (n != -1) {            this.count += n;        }        return n;    }}

 

3.2 解释

  • CountInputStream继承了FilterInputStream,并重写了read()方法来统计读取的字节数。

  • 使用CountInputStream时,可以统计读取的字节总数,通过调用getBytesRead()方法。

3.3 资源管理

使用try-with-resources语法确保流在使用完毕后被正确关闭。这不仅关闭最外层流,还会递归关闭所有嵌套流,确保资源得到释放,避免资源泄漏。

 

 

4. 小结

Java的IO标准库通过Filter模式提供了灵活的方式来扩展InputStreamOutputStream的功能。我们可以将一个基础的流对象与多个功能性流(如缓冲、加密、解压缩等)组合,动态地增加功能。这种方式不仅避免了继承方式带来的类爆炸问题,还提高了代码的复用性和灵活性。

4.1 主要概念

  • Filter模式:通过组合多个流来动态增加功能。

  • 装饰器模式:使用装饰器包装基础流对象,添加附加功能。

  • FilterInputStreamFilterOutputStream:为自定义功能提供基础类,支持流功能的扩展。

通过这些机制,Java的IO系统变得更加强大、灵活和可扩展。


希望通过本文,你能更好地理解Filter模式在Java中的应用,以及如何通过组合流对象来增强功能。如果你在开发中遇到类似的需求,尝试使用这种模式可以让你的代码更加简洁和高效。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值