8

我曾开发过几个尝试遵守 DDD 原则的应用程序,我注意到我们最终会遇到服务层和存储库之间存在重复的情况,感觉就像代码异味。

对于服务层中的大多数操作,它似乎是直接映射到 CRUD 操作、GetAll、GetById、Create、Delete 等。架构的流程在以下几行中:我有一个控制器调用服务层调用一个存储库,该存储库调用一个与后端对话的ORM ..

因此,例如GetAll将同时存在于 SL 和存储库中。现在,如果我们有一个更改/业务要求 GetAll 应该忽略某些项目,我应该怎么做,我应该在存储库中忽略这些,还是应该进入服务层的业务逻辑?如果我们只是有一个直接调用 ORM 的服务层,生活会不会更轻松?

总结一下:我知道服务层可以抽象一些业务逻辑,但是当 - 在大多数情况下 - 它正在处理简单的 CRUD 操作时,摆脱存储库不是更容易吗?但是,如果 SL包含一些具有复杂业务逻辑的方法,这些方法是否应该通过存储库?从良好的设计角度来看,我应该支持一致性并始终通过存储库还是保持简单并且仅在存储库不是简单的一对一映射到 CRUD 操作时才使用它。

PS:我意识到似乎有类似的问题,但没有找到任何令人满意的答案

4

4 回答 4

10

我注意到我们最终会遇到服务层和存储库之间存在重复的情况,这感觉就像代码异味。

这不是代码气味,因为它们做不同的事情。

您应该记住,域或应用程序服务驻留在与存储库实现不同的层中。层的存在是有原因的——不同层中的对象没有相同的职责,也不会与相同的邻居对话。存储库实现与对象的持久性方式紧密耦合。他们可能会生成 SQL 语句并与关系数据库交谈,他们可能会与您的 ORM 交谈……重要的是他们知道您的对象的持久化方式,而应用程序服务并非如此。

如果你的服务层直接调用 ORM,它真的会做两件大事,打破单一职责原则。将您的 ORM 更改为另一种或不同的持久性方式也会更加困难。

因此,例如 GetAll 将同时存在于 SL 和存储库中。现在,如果我们有一个更改/业务要求 GetAll 应该忽略某些项目,我应该怎么做,我应该在存储库中忽略这些,还是应该进入服务层的业务逻辑?

如果 GetAll() 忽略某些项目,我强烈建议在 Service 和 Repository 中重命名它以反映这一点,例如 : GetAllAllowedToUser(), GetAllBut...()。因此,该方法的合同将是明确的,并且您将避免对它应该返回的内容产生误解。另外,您将能够保留原始真正的 GetAll() 方法,该方法仍有一些用处。

于 2012-09-17T08:47:41.227 回答
9

在大多数情况下 - 它处理简单的 CRUD 操作,摆脱存储库不是更容易吗

恕我直言,我不会说要摆脱存储库。我会说,如果你在做 CRUD,你根本不需要 DDD。如果您阅读 Fowler 的企业模式或 Evans,他们都说 DDD 仅在您拥有非常复杂的域逻辑时才有用。CRUD 并不复杂,因此不需要 DDD。

您描述的是代码气味。但我不认为这是 DDD 的气味。您只是看到了一段过度设计的代码。

于 2012-09-16T17:46:55.233 回答
4

为 Dtryon +1,还有:

现在,如果我们有一个更改/业务要求 GetAll 应该忽略某些项目

没有直接关系,我知道你只是用它作为例子,但我已经看到了这个确切的东西。请不要以调用 GetAll 的方法结束,但不能获得全部。保留 GetAll,拥有 GetAll,然后拥有 GetAllLive,或 GetAllAvailable 或类似的东西,它会按照它所说的那样做

于 2012-09-16T17:57:05.540 回答
0

也许“查找器模式”(不知道这是否正确)可以解决您的问题。根据CQS(Command-Query-Separation)原则,(IMO,)查询操作根本不是“业务逻辑”。我们可以在基础设施层写一些特定的“查找器”来执行各种查询,让所有非查询操作(业务逻辑)留在服务层,然后在客户端我们将查找器视为服务。
对不起我的语言:-(。

于 2014-02-02T15:58:31.597 回答