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
的一个简单默认实现。假设ShiftA
和ShiftB
已经实现了。
然后我创建了一个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