Declarative and Immutable Pipeline of Transformations

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

几个月前,我创建了一个小型的Java库,它值得解释,因为它的类和接口的设计非常不寻常。对于一个相当命令式的任务,它非常面向对象:构建一个文档转换的流水线。目标是以声明性和不可变的方式在Java中实现这一点。嗯,尽可能地实现。

假设你有一个文档,还有一系列的转换操作,每个操作都会对文档进行一些处理。例如,每个转换操作都是一小段Java代码。你想要构建一个转换操作列表,然后将文档通过这个列表。

首先,我创建了一个接口Shift(而不是常用且无趣的“transformation”)。

然后我创建了一个接口Train(这是我为转换集合创造的名称),以及它的默认实现。

啊,我忘了告诉你。我是不可变对象的忠实粉丝。这就是为什么Train没有add方法,而是有with方法的原因。区别在于add修改了对象,而with则创建了一个新的对象。

现在,我可以使用TrDefault构建一个包含转换的列车,它是Train的一个简单默认实现。假设ShiftAShiftB已经实现了。

然后我创建了一个Xsline类(它是“XSL” + “pipeline”的组合,因为在我的情况下,我管理XML文档并使用XSL样式表进行转换)。该类的一个实例封装了一个Train的实例,并通过所有的转换将文档传递给它。

So far so good.

现在,我希望所有的转换都能记录自己。我创建了StLogged,它是Shift的装饰器,封装了原始的Shift,装饰了它的apply方法,并在转换完成时向控制台打印一条消息。

现在,我必须做这个:

看起来是new StLogged(的复制,尤其是有几十个shift。为了消除这种重复,我为Train创建了一个装饰器,在运行时装饰封装的shifts,使用StLogged

在我的情况下,所有的转换都是通过XSL转换实现的,从类路径中的文件中获取XSL样式表。这就是代码看起来像这样的原因。

有一个明显的new StXSL(...)的重复,但我不能简单地摆脱它,因为with方法接受一个Shift的实例,而不是一个String。为了解决这个问题,我使Train成为通用类型,并创建了TrClasspath装饰器。

TrClasspath.with() accepts String, turns it into StXSL and passes to TrDefault.with().

请注意上面的代码片段:train 的类型现在是 Train<String>,而不是 Train<Shift>,而 Xsline 需要的是 Train<Shift>。现在的问题是:我们如何回到 Train<Shift>

啊,我忘了提一下。我设计这个库时,有一个重要的原则在2014年提出:所有对象只能实现其接口中的方法。这就是为什么我不能只是在 TrClasspath 中添加一个 getEncapsulatedTrain() 方法。

我引入了一个新的接口Train.Temporary<T>,它有一个返回 Train<T> 的单个方法 back()TrClasspath 类实现了它,我可以这样做:

接下来,我决定消除.with()调用的重复。显然,如果能够提供一个文件名列表作为String数组,并从中构建训练,那将更容易。我创建了一个新的类TrBulk,它正是这样做的。

通过这个设计,我几乎可以以任何可能的方式构建火车。

例如,你可以在这里这里看到我们如何使用它。

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-12-05 at 21:39

sixnines availability badge   GitHub stars