Cactoos 中面向对象的声明式输入/输出

位置:首页>文章>详情   分类: Java教程 > 编程技术   阅读(267)   2023-12-09 07:14:57

Cactoos 是一个面向对象的 Java 原语库,我们 几周前才开始着手开发。目的是为 JDK、Guava、Apache Commons 等提出一个干净且更具声明性的替代方案。我们不想调用静态过程,而是希望使用对象,按照它们应该使用的方式。让我们看看输入/输出如何以面向对象的方式工作。

假设你想读取一个文件。这就是使用 utility class readAllBytes()Files 的方法span> 在 JDK7 中:

byte[] content = Files.readAllBytes(
  new File("/tmp/photo.jpg").toPath()
);

这段代码非常必要——它立即读取文件内容,并将其放入数组中。

这是使用 Cactoos 的方式:

Bytes source = new InputAsBytes(
  new FileAsInput(
    new File("/tmp/photo.jpg")
  )
);

注意——还没有方法调用。只有三个构造函数或三个类组成了一个更大的对象。对象 source 的类型为 Bytes 并表示文件的内容。为了从中获取内容,我们调用它的方法 asBytes()

bytes[] content = source.asBytes();

这是接触文件系统的时刻。如您所见,这种方法是绝对声明式的,因此具有面向对象的所有优点。

这是另一个例子。假设您想将一些文本写入文件。以下是您在 Cactoos 中的操作方法。首先你需要 Input

Input input = new BytesAsInput(
  new TextAsBytes(
    new StringAsText(
      "Hello, world!"
    )
  )
);

然后你需要 Output

Output output = new FileAsOutput(
  new File("/tmp/hello.txt")
);

现在,我们要将输入复制到输出。 OOP 中没有“复制”操作。而且,绝对不能有任何操作。只是对象。我们有一个名为 TeeInput 的类,它是一个 Input,它将您从中读取的所有内容复制到 Output,类似于 Apache Commons 中的 TeeInputStream 所做的,但被封装了。所以我们不复制,我们创建一个 Input 如果你触摸它就会复制:

Input tee = new TeeInput(input, output);

现在,我们必须“触摸”它。我们必须触摸它的每个字节,以确保它们都被复制。如果我们只是read()第一个字节,那么只有一个字节会被复制到文件中。接触它们的最佳方法是逐字节计算 tee 对象的大小。我们有一个对象,叫做 LengthOfInput。它封装了一个 Input 并且表现得像它的字节长度:

Scalar<Long> length = new LengthOfInput(tee);

然后我们从中取出值并进行文件写入操作:

long len = length.asValue();

因此,将字符串写入文件的整个操作如下所示:

new LengthOfInput(
  new TeeInput(
    new BytesAsInput(
      new TextAsBytes(
        new StringAsText(
          "Hello, world!"
        )
      )
    ),
    new FileAsOutput(
      new File("/tmp/hello.txt")
    )
  )
).asValue(); // happens here

这是它在 JDK7 中的替代程序:

Files.write(
  new File("/tmp/hello.txt").toPath(),
  "Hello, world!".getBytes()
);

“为什么面向对象更好,即使它更长?”我听到你问。因为它完美地解耦概念,而过程性概念则将它们放在一起。

比方说,您正在设计一个类,该类应该加密一些文本并将其保存到文件中。以下是您将如何以程序方式设计它(当然不是真正的加密):

class Encoder {
  private final File target;
  Encoder(final File file) {
    this.target = file;
  }
  void encode(String text) {
    Files.write(
      this.target,
      text.replaceAll("[a-z]", "*")
    );
  }
}

工作正常,但是当您决定扩展它以写入 OutputStream 时会发生什么?你将如何修改这个类?之后会难看到什么程度呢?那是因为设计不是面向对象的。

这就是使用 Cactoos 以面向对象的方式进行相同设计的方法:

class Encoder {
  private final Output target;
  Encoder(final File file) {
    this(new FileAsOutput(file));
  }
  Encoder(final Output output) {
    this.target = output;
  }
  void encode(String text) {
    new LengthOfInput(
      new TeeInput(
        new BytesAsInput(
          new TextAsBytes(
            new StringAsText(
              text.replaceAll("[a-z]", "*")
            )
          )
        ),
        this.target
      )
    ).asValue();
  }
}

如果我们希望 OutputStream 被接受,我们如何处理这个设计?我们只添加一个 secondary 构造函数:

class Encoder {
  Encoder(final OutputStream stream) {
    this(new OutputStreamAsOutput(stream));
  }
}

完毕。这就是它的简单和优雅。

这是因为概念是完全分离的,功能是封装的。在程序示例中,对象的行为位于它之外,在方法 encode() 中。文件本身不知道如何写,一些外部程序 Files.write() 知道。

相反,在面向对象的设计中,FileAsOutput 知道如何编写,而没有其他人知道。文件写入功能被封装,这使得以任何可能的方式装饰对象成为可能,创建可重用和可替换的复合对象。

您现在看到 OOP 的美妙之处了吗?

标签2: Java教程
地址:https://www.cundage.com/article/jcg-object-oriented-declarative-inputoutput-cactoos.html

相关阅读

Java HashSet 教程展示了如何使用 Java HashSet 集合。 Java哈希集 HashSet 是一个不包含重复元素的集合。此类为基本操作(添加、删除、包含和大小)提供恒定时间性...
SpringApplicationBuilder 教程展示了如何使用 SpringApplicationBuilder 创建一个简单的 Spring Boot 应用程序。 春天 是用于创建企业应...
通道是继 buffers 之后 java.nio 的第二个主要新增内容,我们在之前的教程中已经详细了解了这一点。通道提供与 I/O 服务的直接连接。 通道是一种在字节缓冲区和通道另一端的实体(通...
课程大纲 Elasticsearch 是一个基于 Lucene 的搜索引擎。它提供了一个分布式的、支持多租户的全文搜索引擎,带有 HTTP Web 界面和无模式的 JSON 文档。 Elasti...
解析器是强大的工具,使用 ANTLR 可以编写可用于多种不同语言的各种解析器。 在这个完整的教程中,我们将: 解释基础:什么是解析器,它可以用来做什么 查看如何设置 ANTLR 以便在 Java...
Java 是用于开发各种桌面应用程序、Web 应用程序和移动应用程序的最流行的编程语言之一。以下文章将帮助您快速熟悉 Java 语言,并迈向 API 和云开发等更复杂的概念。 1. Java语言...
Java中的继承是指子类继承或获取父类的所有非私有属性和行为的能力。继承是面向对象编程的四大支柱之一,用于提高层次结构中类之间的代码可重用性。 在本教程中,我们将了解 Java 支持的继承类型,...
Java Message Service 是一种支持正式通信的 API,称为 网络上计算机之间的消息传递。 JMS 为支持 Java 程序的标准消息协议和消息服务提供了一个通用接口。 JMS 提...
之前,我介绍了spring 3 + hibernate 集成 示例和struts 2 hello world 示例。在本教程中,我将讨论在将 spring 框架与 struts 与 hibern...
Java 项目中的一项常见任务是将日期格式化或解析为字符串,反之亦然。解析日期意味着你有一个代表日期的字符串,例如“2017-08-3”,你想把它转换成一个代表 Java 中日期的对象,例如Ja...