【发布时间】:2015-09-10 10:26:30
【问题描述】:
我有以下情况。用户可以将多种对象类型(交易、发票等)导出到外部会计系统。 导出算法有步骤:
- 通过某些过滤器获取对象
- 将对象一一导出到会计系统(每种对象类型的 Web 服务方法)
- 注册给定文档已导出的事实,因此不会再次导出
- 为用户准备摘要(导出文档的数量、错误消息等)
算法对于所有对象类型都是相同的,但有一些重要的区别必须处理:
- 不同的类型
- 不同的目标 Web 服务方法,不同的对象到 DTO 映射
- 每种对象类型的过滤器不同
我考虑了几个解决方案:
- 不要将导出算法视为代码重复,并为每个对象类型实现一个算法。将任何数据导出到任何外部系统都可以用这种算法来描述——这是否意味着我们应该总是有一个通用类来将任何东西导出到任何地方?:)
- 将差异转移到策略(一个策略接口为所有差异创建抽象) - 我什至实现了它。
- 使用泛型 - 不幸的是,我使用 PHP 进行编码,这是不可能的
问题:
为每个对象类型创建单独的导出算法是否是代码重复?
也许所有这些都应该被视为单独的用例?
如果是重复,那么我应该考虑哪些技术来避免它?
我的第一个实现的描述:
在第一种方法中,我定义了一个可导出的抽象,但我对此并不满意。每个对象都有完全不同的有效载荷。 一个 Exportable 接口只定义了一个方法 getId 并且它用于注册该对象被导出(并且由于它不会再次被导出)。 为此,抽象很好,但问题转移到了 exportService,它必须检查具体实例以选择 DTO 映射器和端点。所以 exportService 破坏了 SOLID。
【问题讨论】:
-
非常好的问题。您是否考虑了用例之间的 «include» 和 «extend» 关系?他们可能会在这里提供帮助。此外,像 Framework、Extensibility 或 Template 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 只有导出方法并且所有差异都隐藏在那里?
标签: oop design-patterns