清洁架构中的实体是否应该了解持久性机制?

时间:2018-06-20 08:17:39

标签: design-patterns architecture unit-of-work clean-architecture

在《清洁建筑》(Robert C. Martin)一书中。 191,他指出“实体是纯粹的业务逻辑,别无其他”。我不确定我应该如何从持久性机制的实体知识方面解释这一说法。

我假设实体对象是有状态的-他们操纵它们表示的业务数据。如果是这样,则必须通知持久层该数据的更改,以便它可以保留这些更改。因此;实体是否可以保留对持久性接口(或工作单元接口,如果设计更为精细的话)的引用?

我倾向于认为拥有这样一个引用(并在实体内部进行调用)的实体对象将不是“纯业务规则”。但是我觉得只要实体持有对接口的引用就不算什么?

如果实体不应该保留对持久性机制的引用,那么是否存在其他用于持久化业务数据更改的良好模式?

5 个答案:

答案 0 :(得分:3)

关于此问题,有2条主要思路。两者都代表着不同的设计模式。这两个选项还都考虑到您正在与建模业务场景各方面的有状态实体打交道,从这种意义上说,它们知道要保留的“数据”,但是,他们不一定知道持久性机制本身

现在,关于持久性机制,第一种实现方式可能是老J2EE或Rails从业者最熟悉的一种方式,在这种方式下,实体完全意识到它将被加载/保存到基础持久性中,并且其接口将传达诸如“获取”,“插入”,“更新”之类的方法。这就是所谓的“活动记录” (马丁·福勒,企业应用程序体系结构的模式)模式。也就是说,实体在为您的业务方面建模时,它还将代表数据库中的直接记录并能够保存/加载自身。

另一种方法将更符合您提到的“清洁体系结构”,一些作者称其为“ “数据映射器” (也是企业应用程序体系结构模式的Martin Fowler)图案。在这种情况下,实体仍然不了解持久性机制(它将是“纯业务逻辑,仅此而已”),并且您将“映射”实体的“数据”委托给外部参与者(类/其他)目前仍在持久性机制/层中。

换句话说,采用这种方法时,您将委派翻译者理解持久性机制以及从数据库到实体以及从实体到数据库的翻译的责任。这样,您的实体就永远不会意识到它们会被保留在其他地方,更不用说这种持久化过程的内部运作了。

持久性数据映射器的界面如下所示:

interface IMyDataMapper {
    void Save(IMyEntity entity);
    IMyEntity Get(whatever criteria you use to find the entity);
}

因此,在该界面中,其职责很明确:

  • 它接收一个实体(不知道此操作),并读取其数据以将其存储在其他位置。
  • 它接收在其他地方查找存储的数据的条件,找到它,然后使用此数据填充实体对象以将其返回给您。

答案 1 :(得分:1)

这主要是基于观点的-您可能会发现有人在投票结束这个问题。

但是...

在我解释引文(以及本书本身,虽然距离阅读本书尚有一段时间)时,其目的不是要定义可直接实施的技术体系结构,而是为您提供一种评估决策的方法。

在频谱的一端,您可能拥有一个将显示,应用程序,业务和持久性逻辑全部混合在一起的组件。我们都可以同意,按照任何标准,这都不是“干净的”,更不用说鲍勃叔叔了。

另一端是纯净,干净的设计,其中业务实体没有提及持久性。例如,您可以通过发送消息/事件来实现。业务实体确定业务流程已完成,并发送一条消息以说明所有内容,然后持久性引擎决定何时以及如何将其写入存储。

根据我的经验,实际上,我们发现自己处于两端之间的某个位置,应该寻求朝着“清洁”迈进,而不是一劳永逸地实现“清洁”。

答案 2 :(得分:0)

我认为,即使您没有进行“干净的体系结构”,您的实体也应该对持久性机制一无所知,因为这些机制可能是可变的,而且可能是任意复杂的。

您提出的问题的解决方案是让正在更改实体的图层还确保这些更改得以保留。

答案 3 :(得分:0)

  他说“实体是纯粹的业务逻辑,别无其他”。我是   不确定我应该如何尊重这一解释   激发持久性机制的知识。

非常文字。

业务对象不应该知道如何持久化。

您的应用程序的体系结构应为:

  • 业务层-包括实体,业务规则,域事件,存储库接口等。
  • 数据层-引用业务层并实现存储库接口。
  • 服务层-引用业务层,协调应用程序的逻辑,并使用业务层中的存储库接口保留数据。

答案 4 :(得分:0)

实体(DTO)不应该知道持久性机制。 因为干净架构的想法是使整个业务逻辑独立于UI和框架。通过了解DTO内部的持久性机制,您的实体将变得依赖于框架。

互动方式应为:

UI <-> VM / Presenter <-> *用例(交互器)<-> *框架上的适配器(插件)

应该在用例和插件之间使用实体。因此,如果驻留在具体用例实现中的业务逻辑对实体进行操作,则它可以直接调用插件方法来保留更改,因为它保留了对该插件的引用。