【问题标题】:Should I always use service, or can I use the repositories directly?我应该始终使用服务,还是可以直接使用存储库?
【发布时间】:2012-01-20 15:22:13
【问题描述】:

当我尝试关注 DDD 时,我是否应该始终通过服务?

或者我可以直接使用存储库来获取域对象吗?

【问题讨论】:

    标签: domain-driven-design


    【解决方案1】:

    就个人而言,我不喜欢在控制器或一般表示层中看到存储库。但是我已经看过很多次了,在 DDD 的上下文中并没有什么问题。

    我认为答案取决于您的项目有多大。服务层更常见于更复杂的项目中。而更简单的 MVC 网站例如只是直接使用存储库。

    【讨论】:

    • “我不喜欢在控制器中看到存储库” => 你能详细说明一下为什么以及在控制器和存储库之间添加什么中间层吗?
    • 控制器会很快变得臃肿。造成这种情况的原因之一是因为开发人员最终将业务逻辑粘贴在他们的控制器中。业务逻辑应该主要只存在于域层,然后是服务层——而不是控制器,也不存在于存储库中。通过在控制器中使用(应用程序)服务,您可以避免这种情况。例如,您可以调用 accountService.GetUserByEmail(email) 或 catalogueService.GetProductViewModel。您的控制器保持良好和精简,您的应用程序服务协调与各种存储库的对话。
    • 仅仅因为您从存储库中获取对象并不意味着您处理业务逻辑。这只是关于从域层获取对象以在另一层中使用。而且我看不出单行 userRepository.GetUserByEmail(email) 如何比 accountService.GetUserByEmail(email) 更膨胀控制器。
    • 如果您告诉我您的 Service 将域对象转换为 ViewModel 对象,那么它可能很有用,但这通常也可以在 Controller 中完成,它不能证明这样一个明确的断言是正确的作为“您不应该在控制器中使用存储库”。除此之外,我看不到这种额外的间接层的好处。
    • 你已经把我的“我不喜欢看到......”变成了“你不应该使用......”。前者意味着偏好。我不是要告诉你该怎么做。你的问题总是会产生一个主观的答案,这里没有对错之分。我说作为一个处理过非常大的控制器的人,我更喜欢并建议将尽可能多的代码保留在控制器之外。我还使用规范模式将我的查询保存在我的领域层中。请参阅this answer 了解更多信息。
    【解决方案2】:

    或者我可以直接使用存储库来获取域对象吗?

    你绝对可以。这正是存储库的目标。我想知道您会为此使用哪种服务(在 SOA 或基于 Web 服务的架构的特定上下文中除外)。

    【讨论】:

    • 我的(预期的)问题是我是否可以绕过服务并直接从存储库中获取域实体(例如在 MVC 控制器中)
    • 嗯,我猜对了,答案是肯定的 :) 有趣的是,如果您查看原始 DDD 书籍和运动现在似乎吓到人们,那么这些被认为是完全正常和普遍的事情......
    • 我不害怕。我只是想知道最佳实践是什么。这本书是九年前出版的,从那以后可能发生了一两件事..
    • 没有最佳实践,只有适合在给定上下文中的实践。现在你写的两行并没有给我们太多的上下文......
    【解决方案3】:

    在完成我的第一个使用 DDD 原则构建的项目后:D,我发现拥有可供应用层使用的域服务和存储库是很有用的。

    要点:应用层可能是您的 WCF 服务或您的 Web 服务中的代码(如果您使用该架构)。这完全取决于您的实施。如果它适合您的实现,您的应用层可能与您的表示层相同,因此在您的控制器或 Web 表单代码中包含应用层代码。

    存储库的功能类似于内存中的集合。对于应用程序层,代码应该看起来就像您只是在使用任何旧集合。

    域服务的功能更像是信息的处理器或访问者,这些信息永远不会被更新,可能会被处理,但不会直接更新。对于应用程序层,代码应该看起来就像您只是在使用任何旧的 Web 服务。

    话虽如此,我会用一些例子来解释更多:

    存储库

    我的存储库实际上继承自一个通用集合,该集合类型是我创建的一个实现对象,该对象将数据库键和业务模型封装在一起。使用这种方法,我可以在我的界面中定义一个索引器,例如

    BusinessObject this[int index];
    

    我可以有一个 getter,它会根据底层集合的索引返回业务对象,还有一个 setter,它会从底层集合中查找数据键并将对象保存到数据库中。这使得应用程序代码非常简单,例如

    IBusinessObjectRepository repository = new SqlBusinessObjectRepository(sqlString);
    BusinessObject obj = repository[0]; //Get first object in the list.
    //Make some changes to the business object by setting properties or calling methods to process business logic.
    repository[0] = obj; //Save the object back to the database.
    

    服务

    我使用服务来检索我不会单独编辑的实体和值对象的列表,在我的情况下,它们仅在调用聚合根上的方法时用作可用的选择或值。通常,我将此信息缓存在 Web 服务器上。这不是域服务的唯一用途,只是我的例子。应用层代码还是比较简单的。

    IBusinessService service = new ImplBusinessService(implementationArgs);
    List<BusinessObject> objsToCache = service.GetBusinessObjects();
    //cache the objects on the web server.
    

    总之,根据我对 DDD 原则的理解,应用层应该能够从服务或存储库访问业务对象。它们之间的选择归结为最适合域模型的内容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-21
      • 2016-12-05
      • 2017-06-10
      • 1970-01-01
      • 1970-01-01
      • 2019-05-03
      • 1970-01-01
      相关资源
      最近更新 更多