【问题标题】:Design pattern for multiple versions of class/algorithm多个版本的类/算法的设计模式
【发布时间】:2017-12-23 20:57:15
【问题描述】:

我正在存储和解析 xml 文件,这些文件会随着时间的推移而演变,因此在存储时我也会存储格式的版本。

当我加载一个 xml 文件时,我会得到文件的版本,并基于这个版本,我使用一个特定的 java 类来处理它。 xml 格式每隔几周就会更改一次,因此正在创建一个新类并将其添加到类列表中。我可以随时加载任何版本的 xml(例如,今天我可以加载两年前使用 v02 版本创建的 xml 文件,而目前是 v26 版本)

这类问题有设计模式吗?是否有针对此类问题使用依赖注入的设计模式?

目前我有一个定义DocumentParser 的java 接口,并且我有几个DocumentParsers,每个都在不同的包中(例如com.parsers.v1.DocumentParserImpl),我有一个提供程序类DocumentParserProvider 来使用版本提供正确的解析器(例如@987654324 @)。接口 api 永远不会改变,也就是说我们总是从我们的接口问同样的事情。

有没有更好的方法或者有这个问题的名称?

【问题讨论】:

  • 正如你在问题中提到的,依赖注入是设计模式。

标签: java design-patterns


【解决方案1】:

根据实际解析所涉及的步骤,也可以申请Template Method pattern(与Strategy相关):

这有点像应用 Don't Repeat Yourself (DRY) 并将解析的公共部分重构为模板方法,并为变化的部分定义多态方法。应用于解析器的上下文:

如果大部分重复代码被隔离到模板方法中,你可以停在那里。正如我在对@Jay 的回答的评论中所写的那样,您应该首先查看您的 XML 文件的每个版本中是否存在某种模式以及它如何影响解析。你可以

  • 只为倾向于变化的部分定义parseOperations(提取方法重构),模板方法parse在正确的时间调用它们。
  • 更进一步,看看parseOperations 自己是否会重复。如果是这样,则将重复的代码放在其他类中(提取类重构以使用组合)。理想情况下,如果发生任何复制/粘贴重复,请将其提取到某种 ParseUtility 类中(或者它可能是抽象类中的静态函数,具体取决于您如何测试/重用它们)。

这种重构方法似乎需要做很多工作,具体取决于 XML 文件版本的变化。在错误修复的情况下,投资可能会得到回报。例如,仅使用策略(并且不重构重复的部分),如果您在 v1 中发现错误并且您必须修复它,那么您可能最终不得不重复错误修复 n em> 次在之后的其他版本中(因为存在错误的代码是复制/粘贴的)。

在很少或没有重复的重构版本中,如果错误在ParseUtil.refactoredRepeatedMethod1() 中被隔离,那么您只需在那里修复一次。

【讨论】:

    【解决方案2】:

    这听起来像是一种策略模式,因为您想使用 Loader 类的不同实现来加载不同的 XML 文件。

    您可以通过应用程序启动一个接一个(或一次反射地)实例化多个 Loader 实例并将它们存储在工厂中。然后你可以要求工厂根据XML版本给你一个Loader


    如果你想使用 DI,你可以有一个 Map<String, Loader> 对象,它只是将 XML 的版本映射到它的加载器。

    【讨论】:

    • 谢谢,我已经使用工厂(DocumentParserProvider)实现了它。我有点担心我的班级组织。我为每个 Loader (DocumentParser) 使用了不同的包,我已经有 29 个了。在这方面有什么最佳实践或更聪明的方法吗?
    • 好吧,我建议他们保持这样:将您的Loader 接口保留在包com.yourcompany.yourapp.xmlloader 中。然后创建像com.yourcompany.yourapp.xmlloader.fooloaderscom.yourcompany.yourapp.xmlloader.barloaders 这样的子包。您还可以提供Loader 接口的默认实现为StandardLoader,或者简单地创建一个实现公共代码的抽象类,但公开受保护的抽象函数以提供定制......数百万种方法来做到这一点:)
    • @awkwardarts 29 个类之间有哪些不同?重复了多少?应用 DRY 原则。查看文本工具中的差异;也许您可以看到经常发生的变化。策略模式假设每个实现都像一个独立的插件,但您不必这样做。一种极端的编程方法可能是每个版本都有一个带有 case 的 switch 语句。如果您以模块化方式分解加载器函数,则可能更易于维护。重复是一种代码味道,许多重构都适用于此。战略只是一个。
    猜你喜欢
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 2021-10-11
    • 2021-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多