应用层还是领域层?


46

我正在阅读Evans的“域驱动设计”,并且正在讨论分层体系结构。我刚刚意识到应用程序层和域层是不同的,应该分开。在我正在从事的项目中,它们是混合在一起的,直到我读完这本书(我现在不能说对我很清楚)之后,我才能分辨出它们之间的区别。

我的问题是,由于这两个问题都涉及应用程序的逻辑,并且应该不涉及技术和表示方面,因此,将这两者划定界限有什么好处?

Answers:


35

我最近亲自阅读了DDD。当我进入本节时,我惊喜地发现我发现了与Evans相同的4层架构。正如@lonelybug指出的那样,域层应与系统的其余部分完全隔离。但是,必须将特定于UI的值(查询字符串,POST数据,会话等)转换为域对象。这就是应用程序层发挥作用的地方。它的工作是在UI,数据层和域之间来回转换,从而有效地将域对系统的其余部分隐藏。

我现在看到许多ASP.NET MVC应用程序,其中几乎所有逻辑都在控制器中。这是实现经典3层体系结构的失败尝试。控制器很难进行单元测试,因为它们具有许多特定于UI的问题。实际上,编写一个控制器使其与“ Http Context”值不直接相关本身就是一个严峻的挑战。理想情况下,控制器应该只是执行翻译,协调工作并吐出响应。

在应用程序层中进行基本验证甚至是有意义的。域可以假设输入其中的值是有意义的(这是此客户的有效ID,并且此字符串表示日期/时间)。但是,涉及业务逻辑的验证(我是否可以保留过去的机票?)应保留给域层。

实际上,马丁·福勒(Martin Fowler)对当今大多数领域层的平坦程度发表了评论。即使大多数人甚至都不知道应用程序层是什么,他发现许多人制作了相当笨拙的域对象和复杂的应用程序层,以协调不同域对象的工作。我自己对此感到内gui。重要的不是要建立一个层,因为有一本书告诉你。这个想法是确定责任并根据这些责任分离我们的代码。就我而言,随着应用程序单元测试的增加,“应用程序层”自然而然地发展了。


9
我认为您在这里所说的不正确:“但是,必须将特定于UI的值(查询字符串,POST数据,会话等)转换为域对象。这就是应用程序层发挥作用的地方”。您所指的是DDD中的“演示”层。应用层应该处理管道,并发和跨领域的问题,只是域层上的一个很小的包装。您所描述的将与表示层中的(子)层相对应。
吞噬了极乐世界

23

从Martin Fowler的企业设计模式中,最常见的层是:

  • 演示文稿-这些是视图,演示文稿模板,它们为您的应用程序生成交互界面(如果其他系统通过Web服务或RMI访问您的应用程序,则我可能会使用交互界面,因此可能不是用户界面)。它还包括决定如何执行动作以及如何执行动作的控制器。

  • 域-这是您的业务规则和逻辑所在,域模型已定义等

  • 数据源-这是数据映射层(ORM)和数据源(数据库,文件系统等)

如何绘制三层之间的界限:


17

领域层模型的业务应用程序。这应该是您对其规则的清晰解释,它是组件的动态特性,并包含其在任何给定时刻的状态。

应用层的“担心”定义需要做的工作以完成一定的应用任务。主要是,它负责授权必要的域工作与其他(外部或非外部)服务进行交互。

对于例如,我的金融软件应用程序具有用于改变模型实体的状态的用户操作(如在DDD定义的实体[89]):

  • “运营总监可以批准财务建议”。

但是,作为一个应用程序过程,除了此操作的所有模型后果外,我还必须向该应用程序的其他用户发送内部通信。这种工作是在应用程序层中“安排”的。我不希望我的域层考虑引导消息服务。(当然这不是表示层的责任)。无论如何,肯定有一件事情:我需要一个新层,因为我的域层全是核心业务,而我的表示层全是解释用户命令和呈现结果。

笔记:

  • 商业是经常引起其含义的多种解释的词语之一,但是可以肯定的是,在DDD中您可以找到很多示例和讨论。
  • DDD代表Eric Evans撰写的《域驱动设计》一书,方括号内的数字代表页码。

6

域层应设计为隔离层,这意味着业务逻辑和规则不应受到任何代码更改(在应用程序层,表示层和基础结构层中)的影响。

假定应将应用程序层设计为提供一些有关系统(应用程序)接口(例如API或RESTful)的功能。例如,用户可以登录系统,并且在此应用程序操作(登录)中,应用程序层代码将是域层(或基础结构层)的客户端代码,在其中检索用户域对象并应用该对象的方法来实现“登录”功能。

应用程序层还应该设计为隔离层,这意味着应用程序的行为不应受到任何代码更改(在表示层,域层和基础结构层中)的影响。


2
至少在诸如领域驱动设计(Evans)之类的文献中,人们已经认识到这些层具有单向依赖关系 ……事实上,在某些时候,您的代码依赖于某种东西。用户界面取决于应用程序,反之则不然。应用程序取决于域,而不取决于域。基础架构上的域,反之亦然。

1
依赖性与编程方式有关,隔离层与设计系统层有关。一种依赖性在这里没有打破隔离的概念,因为在编程时,顶层代码应依赖于下层的接口而不是实现类。
stevesun13年

很好,而且全部都写在纸上,但是实际上,业务需求导致的更改会影响应用程序层的界面,从而使更改在整个表示层中冒出气泡,有时甚至到存储层。那就是我要得到的一切……

隔离层设计并不意味着将来不允许进行任何更改。相反,它使更改变得更加容易-更容易测试和估计工作。是的,新的业务需求意味着您可能需要从上到下进行更改,这不是您以前实现现有功能的方式吗?如果您可以基于SOLID原理设计每一层,那么您可能会发现您可以重复使用底层的现有功能。
stevesun21

3

域驱动建模的重点是将基本域模型分离出来并使其存在而又不依赖于其他层和其他应用程序问题。

这使您可以专注于域本身而不会分散注意力(例如在UI和持久性服务之间进行协调)。


然后,数据源(ORM)在域内部吗?
Maykonn 2013年

@Maykonn-可能是。但是,ORM不是数据源。它是您的代码和实际数据源(关系数据库)之间的工具。如何访问数据不应该是域的问题-建设者和工厂可以处理该问题(如果有ORM,则可以使用ORM)。
Oded

我同意。我对数据源和ORM错了。谢谢!
Maykonn 2013年

3
  • 应用层域层都属于实现范围。
  • 应用层充当API。
  • 域层是API的实现,它包含业务逻辑,因此也称为业务逻辑层。

在此处输入图片说明


从来没有这样。...我感到很高兴
Nikos

2

这些界限的主要原因是关注点分离。访问数据存储区的代码只需要担心访问数据存储区。它不应负责对数据执行规则。此外,UI应该负责更新UI中的控件,从用户输入中获取值并将它们转换为域层可以使用的内容,仅此而已。它应调用域层提供的操作以执行任何所需的操作(例如,保存此文件)。调用的Web服务应负责将传输介质转换为域层可以使用的内容,然后调用域层(大多数工具可以为您完成很多工作)。

如果正确实现了这种分离,则可以使您能够更改部分代码而不会影响其他代码。例如,可能需要更改返回的对象集合的排序顺序。由于您知道负责数据操作的层(通常是业务逻辑层)可以处理这些内容,因此您可以轻松地确定需要在哪里更改代码。不必修改如何从数据存储区或使用该域的任何应用程序中检索它的方式(上面示例中的UI和Web服务)。

最终目标是使您的代码尽可能易于维护。

附带说明一下,有些事情无法深入到域的特定层中(例如,日志记录,验证和授权)。这些项目通常称为跨领域关注点,在某些情况下,可以将其视为独立存在的一层,所有其他层都可以看到和使用。

我个人认为分层方法已经过时,并且服务方法更好。您仍然可以清楚地看出谁在做什么,但这并不会迫使您成为分层的人。例如,一个采购订单服务,一个开票服务和一个运输服务,从应用程序的角度来看,所有这些服务都代表您的域,而我上面描述的责任延期在这种情况下仍然有效,它已经被更改为您的域存在于多个地方,进一步利用关注点分离概念。


我一直对授权逻辑的位置感到好奇,从我试图理解的范围来看,它适合于“应用程序层”。您是否愿意就为什么最好不要将其包含在该逻辑层中分享一些见解?

1
这是此网站的理想类型。您应该发布它,以便每个人都有机会回答。
查尔斯·兰伯特

@tuespetre您能否提供该帖子的链接?
drizzie 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.