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

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

假设您要读取文件。 这是使用JDK7中的实用程序类“ Files中的静态方法readAllBytes()方法:

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所做的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被接受,我们该怎么做? 我们只添加一个辅助构造函数:

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

做完了那是多么容易和优雅。

那是因为概念被完美地分离并且功能被封装了。 在该过程示例中,该对象的行为位于方法外部(在encode()方法中encode() 。 文件本身不知道如何写,某些外部过程Files.write()知道。

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

您现在看到OOP的美丽了吗?

翻译自: https://www.javacodegeeks.com/2017/06/object-oriented-declarative-inputoutput-cactoos.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值