如何在不损害 java + PDFBox 中的 DRY 原则的情况下格式化代码?

How to go about formatting code without hurting the DRY principle in java + PDFBox?

请原谅这个问题的阴暗面,请允许我自己解释一下。

我使用 PDFBox 创建了一个 PDFGenerator。 PDF 大约有 9 页,实际 PDFGenerator.java 是一个拥有近 4k 行代码的怪物,大部分代码是 PDF 中文本的恒定像素定位。

当前版本 (v1) 包括 2 个主要变量,供应和排放。因此,对于某物的每一行,都有一个供给值和一个耗尽值。

整个过程非常完美,我对整个生成过程非常满意。然而,现在 v2 已经到来,客户希望有可能创建 供应或排放,或两者

这就是我的 DRY 原则问题所在。理论上,两者的代码已经存在。当它是一个或另一个时,唯一改变的是文本的定位,它现在在两列之间居中。

示例:两者(当前正在生成)

属性........................... 排气

身高................................5................. ...5

宽度 .....................................5................ ....5

示例:一个或另一个

属性......................供应......

身高......................................5....... .........

宽度......................................5...... .........

这是一个生成一行的块:

    pdContentStream.beginText();
    pdContentStream.setFont(boldFont, BOLD_FONT_SIZE);
    pdContentStream.newLineAtOffset(TEXT_BEGIN, currentYCoord);
    pdContentStream.showText(messageSource.getMessage("pdf.value.TDVentilator", null, this.locale));
    pdContentStream.endText();

    pdContentStream.beginText();
    pdContentStream.setFont(boldFont, BOLD_FONT_SIZE);
    pdContentStream.newLineAtOffset(SUPPLY_BEGIN, currentYCoord);
    pdContentStream.showText(messageSource.getMessage("pdf.supply", null, this.locale));
    pdContentStream.endText();

    pdContentStream.beginText();
    pdContentStream.setFont(boldFont, BOLD_FONT_SIZE);
    pdContentStream.newLineAtOffset(EXHAUST_BEGIN, currentYCoord);
    pdContentStream.showText(messageSource.getMessage("pdf.exhaust", null, this.locale));
    pdContentStream.endText();

请记住,这些块在整个生成过程中会重复出现。现在是我的 DRY 问题出现的地方。

我想到的第一件事是将当前代码导出到一个仅用于生成两者的函数,然后创建 (copy/paste) 用于一个或另一个的第二个函数。但是大部分代码会重复执行此操作(少一个块,因为我们只有一个输出变量,而不是两个)。

我能想到的另一种方法是在每个代码块之前创建一个 if() ,如果是这种情况,则取该块,如果是,则取该块。再一次,DRYness 不存在(因为相同的 if 必须出现在每个代码块之前)。

我的问题是:通常最好的方法是什么?我不介意这个怪物是否再次从 4k 行代码增长到 8k 行代码,但如果有更简单(更好)的方法来做到这一点,我会洗耳恭听。

干杯 :)

查看您的代码:

pdContentStream.beginText();
pdContentStream.setFont(boldFont, BOLD_FONT_SIZE);
pdContentStream.newLineAtOffset(EXHAUST_BEGIN, currentYCoord);
pdContentStream.showText(messageSource.getMessage("pdf.exhaust", null, this.locale));
pdContentStream.endText();

我看到的只有部分是给messageSource.getMessage()的第一个参数。

所以您的重构可能会从引入开始:

public void prepareContent(Whatever pdContentStream, String message) {
    pdContentStream.beginText();
    pdContentStream.setFont(boldFont, BOLD_FONT_SIZE);
    pdContentStream.newLineAtOffset(EXHAUST_BEGIN, currentYCoord);
    pdContentStream.showText(messageSource.getMessage(message, null, this.locale));
    pdContentStream.endText();
}

然后您的主要代码归结为:

prepareContent(pdContenStream, "pdf.value.TDVentilator");
prepareContent(pdContenStream, "...

等等。然后:您可能会将这些东西放在它自己的 class 中,在其中您将 pdContentStream 设为一个字段;到 git 摆脱每次调用都需要该参数。

之后应该更好地研究 "organizing" 那些字符串。写下来没有意义:

foo("bla");
foo("blub");

相反,您将 "pdf.value.TDVentilator" 之类的值推送到 List 中;然后暗示迭代 lists/sets/whatever,从那里获取所需的信息。

长话短说:你不会培养怪物。你甚至不允许它们存在。您显示的代码已经 严重 违反了 DRY,绝对 不能 是可以容忍的!