首页 > 编程语言 >39 | JAVA_IO_Filter模式(Decorator模式)-cnblog

39 | JAVA_IO_Filter模式(Decorator模式)-cnblog

时间:2022-09-05 19:44:06浏览次数:66  
标签:39 JAVA int 模式 InputStream read FilterInputStream FileInputStream

Filter模式(Decorator模式)

为了解决依赖继承会导致子类数量失控的问题,JDK首先将InputStream分为两大类:

一类是直接提供数据的基础InputStream,例如:

  • FileInputStream
  • ByteArrayInputStream
  • ServletInputStream
  • ...

一类是提供额外附加功能的InputStream,例如:

  • BufferedInputStream
  • DigestInputStream
  • CipherInputStream
  • ...

当我们需要给一个“基础”InputStream附加各种功能时,我们先确定这个能提供数据源的InputStream,因为我们需要的数据总得来自某个地方,例如,FileInputStream,数据来源自文件:

InputStream file = new FileInputStream("test.gz");

紧接着,我们希望FileInputStream能提供缓冲的功能来提高读取的效率,因此我们用BufferedInputStream包装这个InputStream,得到的包装类型是BufferedInputStream,但它仍然被视为一个InputStream

InputStream buffered = new BufferedInputStream(file);

最后,假设该文件已经用gzip压缩了,我们希望直接读取解压缩的内容,就可以再包装一个GZIPInputStream

InputStream gzip = new GZIPInputStream(buffered);

无论我们包装多少次,得到的对象始终是InputStream,我们直接用InputStream来引用它,就可以正常读取:

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

上述这种通过一个“基础”组件再叠加各种“附加”功能组件的模式,称之为Filter模式(或者装饰器模式:Decorator)。它可以让我们通过少量的类来实现各种功能的组合:

                 ┌─────────────┐
                 │ InputStream │
                 └─────────────┘
                       ▲ ▲
┌────────────────────┐ │ │ ┌─────────────────┐
│  FileInputStream   │─┤ └─│FilterInputStream│
└────────────────────┘ │   └─────────────────┘
┌────────────────────┐ │     ▲ ┌───────────────────┐
│ByteArrayInputStream│─┤     ├─│BufferedInputStream│
└────────────────────┘ │     │ └───────────────────┘
┌────────────────────┐ │     │ ┌───────────────────┐
│ ServletInputStream │─┘     ├─│  DataInputStream  │
└────────────────────┘       │ └───────────────────┘
                             │ ┌───────────────────┐
                             └─│CheckedInputStream │
                               └───────────────────┘

类似的,OutputStream也是以这种模式来提供各种功能:

                  ┌─────────────┐
                  │OutputStream │
                  └─────────────┘
                        ▲ ▲
┌─────────────────────┐ │ │ ┌──────────────────┐
│  FileOutputStream   │─┤ └─│FilterOutputStream│
└─────────────────────┘ │   └──────────────────┘
┌─────────────────────┐ │     ▲ ┌────────────────────┐
│ByteArrayOutputStream│─┤     ├─│BufferedOutputStream│
└─────────────────────┘ │     │ └────────────────────┘
┌─────────────────────┐ │     │ ┌────────────────────┐
│ ServletOutputStream │─┘     ├─│  DataOutputStream  │
└─────────────────────┘       │ └────────────────────┘
                              │ ┌────────────────────┐
                              └─│CheckedOutputStream │
                                └────────────────────┘

编写 FilterInputStream

我们也可以自己编写FilterInputStream,以便可以把自己的FilterInputStream“叠加”到任何一个InputStream中。

下面的例子演示了如何编写一个CountInputStream,它的作用是对输入的字节进行计数:

import 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;
    }

    public int read() throws IOException {
        int n = in.read();
        if (n != -1) {
            this.count ++;
        }
        return n;
    }

    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;
    }
}

注意到在叠加多个FilterInputStream,我们只需要持有最外层的InputStream,并且,当最外层的InputStream关闭时(在try(resource)块的结束处自动关闭),内层的InputStreamclose()方法也会被自动调用,并最终调用到最核心的“基础”InputStream,因此不存在资源泄露。

标签:39,JAVA,int,模式,InputStream,read,FilterInputStream,FileInputStream
From: https://www.cnblogs.com/mmxingye/p/16659325.html

相关文章

  • 【Java基础】package、import关键字和JDK中主要包
    1.package声明在源文件首行,每一个.表示一层文件夹,指明该类所在包,包名通常都小写。根据项目需要将代码放在不同包中2.import(1)导入指定包下所需要的类、接口,xxx.*表示......
  • Java 使用技巧-如何抛出一个异常并捕获它
    工作中需要使用Java编写插件,但并不是主要技术栈,所以简单地学习记录一下。背景与Javascript不同,Java中类型的概念非常强,函数中不能返回与声明不同类型的返回值。例如下面......
  • 【Java基础】关键字this
    1.this是什么this是一个对象,表示当前对象或当前正在创建的对象2.使用在类的方法中,使用this.属性或this.方法调用当前对象属性或方法,但一般都省略。方法的形式参数和类......
  • python a+模式读取文件时内容为空
    1.pythona+模式打开文件,然后直接读取,这时候读取出来的内容为空----为什么呢?这是因为打开时是以追加的模式打开的,这时候光标定位在最后,此时读取readline,吃从当前光标开......
  • 【Java基础】JavaBean是什么
    1.JavaBean是什么符合如下标准的Java类类是公共的public有一个无参的公共的构造器有属性,且有对应的get、set方法2.示例publicclassJavaBean{privateStrin......
  • 【Java基础】类的结构之三:构造器(构造方法)
    1.构造器是什么也称为构造方法、构造函数。(1)方法名与类名相同(2)没有返回值类型(3)不能被static、final、synchronized、abstract、native修饰publicclassCircle{......
  • 阿里 Seata 新版本终于解决了 TCC 模式的幂等、悬挂和空回滚问题
    简介: 今天来聊一聊阿里巴巴Seata新版本(1.5.1)是怎么解决TCC模式下的幂等、悬挂和空回滚问题的。作者:朱晋君 大家好,我是君哥。 今天来聊一聊阿里巴巴S......
  • gym.error.NameNotFound: Environment PongNoFrameskip doesn't exist.
    解决办法经过多处搜索找到的解决办法!主要参考的是参考链接2。出现这种错误的主要原因是安装的gym不够全。我一开始下载gym库的时候输入的是pipinstallgym后来才知......
  • JavaDoc
    JavaDocjavadoc命令是用来生成自己API文档的参数信息:@author作者名@version版本号@since指明需要最早使用的jdk版本@param参数名@return返回值情况......
  • MySQL 行锁观察模式8.0
    全新的MySQL8.0新增了全新的锁观测方式,在performance_schema下新增了data_locks表和data_lock_waits表mysql>showtableslike'%data_lock%';+-----------------------......