建议使用简洁的类模型/模式来解决方法中的多个小变化


Suggestions for concise class model / pattern to solve multiple minor-variations in methods

我有一堆数据库报告需要实现,未来还会有更多,所以我对构建可扩展代码和避免重复的逻辑和代码特别感兴趣。我在PHP中实现,但问题更普遍。除了PHP之外,还可以用Java、c++、c#等语言发布示例。

我面临的问题是,报告的差异太大了,我不能轻易地组合所有构建SQL的代码,构建HTML输出就更困难了。例如,一个报表包含一列长文本消息,需要css样式并启用javascript以使鼠标停留显示整个消息,而其他报表包含值转换为百分比的列,或有条件地显示为"小于1%"并累计到"其他"类别。

所以我从一个策略模式开始。我的类模型的一个非常简单的草图可以在这里看到:http://static.inky.ws/image/4044/ClassDiagram.png

我有一个抽象的报告,以及每个报告类型的具体实现。报表有两个属性,它们引用封装的功能(通过接口的具体实现),用于不同的SQL构建器和每个报表的输出数据格式。但这开始让每个报告看起来有太多类了。有没有更好的方法来解决这个问题?

实现上述模型的代码草图:

<?php
abstract class Report {
   private $sqlBuilder = null;
   private $dataFormatter = null;
}
class ReportOne extends Report {
   public function __constructor() {
       $this->sqlBuilder = new ReportOneSqlBuilder();
       $this->dataFormatter = new ReportOneDataFormatter();
}
class ReportTwo extends Report {
   // similar to ReportOne
}
interface SqlBuilder {
}
class ReportOneSqlBuilder implements SqlBuilder {
}
class ReportTwoSqlBuilder implements SqlBuilder {
}
interface DataFormatter {
}
class ReportOneDataFormatter {
}
class ReportTwoDataFormatter {
}
?>

这个想法是将所有的通用代码保留在抽象类中,而将具体的差异保留在各个具体的子类中。我在写这篇文章时突然想到,我还需要SQL和数据格式化的抽象类,因为接口不能真正携带任何实现细节。

有时最好保持两个相似但有重要区别的东西,彼此完全分开,即使这违反了DRY(不要重复自己)原则。

事实上这是有充分理由的。重要的是,如果您试图重用代码的某些部分,并且稍后您需要修改一些只会影响其中一个报告的内容,那么无论如何您都必须破坏公共代码。

设计模式是可爱的,当然有它们的用途,然而,在某些情况下,最好使用不同的逻辑,可能部分重复自己,并保持代码尽可能简单。比DRY更重要的是代码的可读性,如果你为了一个不需要复杂的特性而使你的代码复杂化,你会损害你的可读性,几乎没有收获。

如果您真的认为这两个报告有很强的相似性,并且值得将您的应用程序复杂化,或者如果您这样做是为了练习您的设计模式实现技能,那么就去做吧。如果您只是想高效地完成工作,并使您的应用程序易于修改,只需保持简单并使用两种不同的逻辑。