实现类似的用例看起来像代码重复

Posted

技术标签:

【中文标题】实现类似的用例看起来像代码重复【英文标题】:Implementing similar UseCases looks like code duplication 【发布时间】:2015-09-10 10:26:30 【问题描述】:

我有以下情况。用户可以将多种对象类型(交易、发票等)导出到外部会计系统。 导出算法有步骤:

通过某些过滤器获取对象 将对象一一导出到会计系统(每种对象类型的 Web 服务方法) 注册给定文档已导出的事实,因此不会再次导出 为用户准备摘要(导出文档的数量、错误消息等)

算法对于所有对象类型都是相同的,但有一些重要的区别必须处理:

不同的类型 不同的目标 Web 服务方法,不同的对象到 DTO 映射 每种对象类型的过滤器不同

我考虑了几个解决方案:

不要将导出算法视为代码重复,并为每个对象类型实现一个算法。将任何数据导出到任何外部系统都可以用这种算法来描述——这是否意味着我们应该总是有一个通用类来将任何东西导出到任何地方?:) 将差异转移到策略(一个策略接口为所有差异创建抽象) - 我什至实现了它。 使用泛型 - 不幸的是,我使用 php 进行编码,这是不可能的

问题:

为每个对象类型创建单独的导出算法是否是代码重复?

也许所有这些都应该被视为单独的用例?

如果是重复,那么我应该考虑哪些技术来避免它?

我的第一个实现的描述:

在第一种方法中,我定义了一个可导出的抽象,但我对此并不满意。每个对象都有完全不同的有效载荷。 一个 Exportable 接口只定义了一个方法 getId 并且它用于注册该对象被导出(并且由于它不会再次被导出)。 为此,抽象很好,但问题转移到了 exportService,它必须检查具体实例以选择 DTO 映射器和端点。所以 exportService 破坏了 SOLID。

【问题讨论】:

非常好的问题。您是否考虑了用例之间的 «include»«extend» 关系?他们可能会在这里提供帮助。此外,像 FrameworkExtensibilityTemplate Method 这样的模式可以替代您的实现方法。 首先,您应该将过滤和导出视为两个不同的问题。您通常希望将差异移至策略,然后根据 API 的设计方式将策略选择隐藏在 Facade/Factory 后面。例如,客户端可能只做exportService.export(listOfExportable),但在内部根据Exportable 的类型,将选择一个Web 服务端点以及一个dto 汇编器。导出服务可以从外部进行配置,以避免违反开闭原则。您也可以将策略选择放在 Exportable 让导出对象指定策略的好处是可以避免在导出服务中使用服务定位器模式。 exportService 可以在Exportable 上进行双重调度以收集信息。同时,也有一个缺点,因为基础设施问题可能会在不应该泄露的层中泄露。这与“我应该将 ORM 注释放在实体中还是应该使用外部 XML 文件?”类似的斗争。 模板方法是一种听起来可能适用于此处的模式。 en.wikipedia.org/wiki/Template_method_pattern @plalx 我添加了对创建抽象“可导出”的第一种方法的描述以及它失败的原因。回到你的评论。您的意思是将对象包装到某个具体的 Exportable 实现中,其中 Exportable 只有导出方法并且所有差异都隐藏在那里? 【参考方案1】:

您上面描述的所有内容都不是特定于域的逻辑(实际上您甚至没有在问题中提及问题域),因此我认为它并不真正属于域驱动设计。因为它不是特定领域的逻辑,所以我不会太担心代码重复,特别是考虑到解决方案似乎并不明显。

保持简单,只需分别写出每个用例。如果您发现有很容易重构的通用代码,请在一切顺利后进行。在明显有必要之前不要想太多或添加模式。

【讨论】:

可能是他主域的子域。 “注册给定文档已导出的事实,因此不会再次导出” 是域逻辑 IMO。

以上是关于实现类似的用例看起来像代码重复的主要内容,如果未能解决你的问题,请参考以下文章

测试新人如何使用Python代码封装自动化测试的用例?

FutureProvider 的用例

行为驱动:Cucumber + Selenium + Java - 实现测试用例的参数化

测试新人如何使用Python代码封装自动化测试的用例

pytest为什么不能运行指定目录下的用例

一个类或对象的“sizeof”可以为零吗?