清洁架构中的实体应该知道持久性机制吗?

Should Entities in Clean Architecture know of persistence mechanisms?

在书中 'Clean Architecture'(罗伯特·C·马丁)p. 191,他说 "Entity is pure business logic and nothing else"。我不确定我应该如何根据持久性机制的实体知识来解释这个陈述。

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

我倾向于认为持有这样一个引用(并从实体内部调用它)的实体对象不是 'pure business rules'。但我觉得只要实体持有对接口的引用就不算数?

如果实体不应该持有对持久性机制的引用,是否有任何其他好的模式来持久化对业务数据的更改?

我认为,即使您不执行 Clean Architecture,您的实体也应该对持久性机制一无所知,因为这些机制可能是可变的并且任意复杂。

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

这主要是基于意见 - 您可能会发现人们投票结束这个问题。

然而...

当我解释这句话(和这本书本身,虽然我读它已经有一段时间了)时,目的不是定义一个直接可实现的技术架构,而是给你一种评估你的决定的方法。

在光谱的一端,您可能拥有一个将显示、应用程序、业务和持久性逻辑全部混合在一起的组件。我们都同意这不是任何标准的 "clean",更不用说 Bob 叔叔的了。

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

根据我的经验,实际上,我们发现自己处于这两个端点之间的某个位置,应该寻求向 "clean" 迈进,而不是一口气达到 "cleanliness"。

关于这个问题有两种主要的思路。它们都代表了不同的设计模式。这两个选项还考虑到您正在处理有状态实体,这些实体对您的业务场景的各个方面进行建模,从这个意义上说,他们知道将被持久化的 "data" 但是,他们不一定知道持久性机制本身。

现在,关于持久性机制,第一种方法可能是旧 J2EE 或 Rails 从业者最熟悉的,实体完全意识到它将 loaded/saved底层持久化及其接口将传达 "get"、"insert"、"update" 等方法。这被称为 "Active Record"(Martin Fowler,企业应用程序架构模式)模式。也就是说,实体在为您的业务的一个方面建模时,它也将代表数据库中的一条直接记录,并且能够 save/load 本身。

另一种方法更符合您提到的 "Clean Architecture",一些作者将其称为 "Data Mapper"(还有 Martin Fowler ,企业应用架构模式)模式。就此而言,实体仍然不知道持久性机制(它将是 "pure business logic, and nothing else"),并且您将 "mapping" 和 [=33= 的责任委托给外部参与者(class / 其他) ] 实体当前持有和退出持久性 mechanism/layer.

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

持久性数据映射器的接口将是这样的:

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

所以,从那个接口来看,它的职责很明确:

  • 它接收一个实体(它不知道此操作)并读取其数据以将其存储在其他地方。
  • 它接收在其他地方查找存储数据的标准,找到它并用该数据填充实体对象以return它给你。

he states that "Entity is pure business logic and nothing else". I am unsure of how literal I should interpret this statement with respect to the entites knowledge of a persistence mechanism.

非常直白。

业务对象不应该知道它们是如何被持久化的。

您的应用程序的架构应该是:

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

实体(DTO)不应该知道持久化机制。 因为干净架构的思想是让你的整个业务逻辑独立于 UI 和框架。通过在 DTO 中提供持久性机制的知识,您的实体将变得依赖于框架。

交互应该是这样的:

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

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