为什么要将我的域实体与表示层隔离?

Mar*_*ers 83 architecture design-patterns domain-driven-design data-transfer-objects presentation-layer

域驱动设计的一部分似乎没有太多细节,是您应该如何以及为什么要将域模型与界面隔离开来.我试图说服我的同事,这是一个很好的做法,但我似乎没有取得多大进展......

他们在演示文稿和界面层中随意使用域实体.当我向他们争辩说他们应该使用显示模型或DTO来将Domain层与接口层隔离时,他们反驳说他们在做类似的事情时看不到业务价值,因为现在你有一个UI对象要维护以及原始域对象.

所以我正在寻找一些可以用来支持它的具体原因.特别:

  1. 我们为什么不在表示层中使用域对象?
    (如果答案是明显的,'脱钩',那么请解释为什么这在这方面很重要)
  2. 我们应该使用其他对象或构造来将我们的域对象与接口隔离吗?

Pau*_*ier 46

很简单,原因是实现和漂移.是的,您的表示层需要了解您的业务对象才能正确表示它们.是的,最初看起来两种类型的对象的实现之间存在很多重叠.问题是,随着时间的推移,双方都会增加一些东西.演示文稿更改以及表示层的需求演变为包括完全独立于业务层(例如颜色)的内容.同时,您的域对象会随着时间的推移而发生变化,如果您没有从界面中进行适当的分离,则可能会通过对业务对象进行看似良性的更改来调整界面层.

就个人而言,我认为处理事情的最佳方式是通过严格执行的界面范式; 也就是说,您的业务对象层公开了一个接口,这是与之通信的唯一方式; 没有公开关于接口的实现细节(即域对象).是的,这意味着您必须在两个位置实现域对象; 你的界面层和你的BO层.但是这种重新实现虽然最初可能看起来像是额外的工作,但却有助于强化解耦,这将在未来的某个时刻节省大量的工作.

  • @LuckyLindy:100次中99次(实际上更多),系好安全带没有必要让我免受伤害.然而,在我真正需要它的一个例子中,它(可能)会让我免于被杀或严重受伤.一盎司的预防值得一磅治疗.我怀疑你有这方面的意见会在你有更多经验后改变. (12认同)
  • 这对我来说似乎很愚蠢.为什么现在额外的工作可以节省未来的工作?10次​​中有9次你永远不需要做出能够节省"TONS"工作的改变. (10认同)
  • "在两个位置实现域对象是什么意思?" (2认同)

Jos*_*rke 19

我自己也在努力解决这个问题.在某些情况下,DTO在演示中使用是有意义的.假设我想在我的系统中显示公司的下拉,我需要他们的id来绑定值.

好吧,我可以发送一个带有名称和ID的DTO,而不是加载可能引用订阅的CompanyObject或者知道其他什么的CompanyObject.这是一个很好用的恕我直言.

现在再看一个例子.我有一个表示估计的对象,这个估计可能由人工,设备等组成,它可能有很多由用户定义的计算,它们采用所有这些项并将它们相加(每个估计可能因不同的类型而不同)计算).我为什么要两次模拟这个对象?为什么我不能简单地让我的UI枚举计算并显示它们?

我通常不使用DTO来从我的UI中隔离我的域层.我使用它们来隔离我的域层与我无法控制的边界.有人将导航信息放入其业务对象的想法是荒谬的,不要污染您的业务对象.

有人会在其业务对象中进行验证的想法?好吧,我说这是件好事.您的用户界面不应单独负责验证您的业务对象.您的业​​务层必须自己进行验证.

为什么要将UI生成代码放在业务对象中?在我的情况下,我有单独的对象,从UI生成UI代码seperatley.我有一些对象将我的业务对象渲染成Xml,你必须分离你的图层以防止这种类型的污染对我来说是如此陌生,因为为什么你甚至将HTML生成代码放在业务对象中......

编辑 正如我想的那样,有些情况下UI信息可能属于域层.这可能会覆盖你所谓的域层,但我在一个多租户应用程序上工作,它具有非常不同的行为,包括UI外观和功能工作流.取决于各种因素.在这种情况下,我们有一个代表租户及其配置的域模型.他们的配置恰好包括UI信息(例如,通用字段的标签).

如果我必须设计我的对象以使它们可以持久化,我是否还必须复制对象?请记住,如果您想要添加新字段,现在有两个地方可以添加它.也许这会引发另一个问题,如果您使用DDD,都是持久化实体域对象?我在他的例子中知道他们是.


dig*_*oel 16

您这样做是出于将SQL保留在ASP/JSP页面之外的原因.

如果只保留一个域对象,以便在表示AND域层中使用,那么这个对象很快就会变成单一的.它开始包括UI验证代码,UI导航代码和UI生成代码.然后,您很快就会添加所有业务层方法.现在,您的业务层和UI都混淆了,所有这些都在域实体层混乱.

您想在另一个应用程序中重用那个漂亮的UI小部件吗?好吧,你必须用这个名字,这两个模式和这18个表创建一个数据库.您还必须配置Hibernate和Spring(或您选择的框架)来进行业务验证.哦,你还必须包括这85个其他非相关类,因为它们在业务层中引用,它恰好位于同一个文件中.


Dan*_*iuc 13

我不同意.

我认为最好的方法是从表示层中的域对象开始,直到它做出其他方式的意见.

与流行的看法相反,"域对象"和"价值对象"可以愉快地共存于表示层中.这是最好的方法 - 你可以获得两个世界的好处,减少与域对象的重复(和样板代码); 以及在请求中使用值对象的定制和概念简化.


Mar*_*zak 5

答案取决于您的应用程序规模。


简单的CRUD(创建,读取,更新,删除)应用程序

对于基本的Crud应用程序,您没有任何功能。在实体之上添加DTO会浪费时间。这将增加复杂性而不增加可伸缩性。

在此处输入图片说明


中等复杂的非CRUD应用

在这种规模的应用程序中,您将很少有具有真正生命周期的实体以及与之关联的一些业务逻辑。

出于以下几个原因,在这种情况下添加DTO是一个好主意:

  • 表示层只能看到实体具有的字段子集。您封装实体
  • 后端与前端之间没有耦合
  • 如果您在实体内部有业务方法,但在DTO中没有,那么添加DTO意味着外部代码不会破坏您实体的状态。

在此处输入图片说明


复杂的企业应用

单个实体可能需要多种表示方式。他们每个人都需要不同的字段集。在这种情况下,您会遇到与上一个示例相同的问题,并且需要控制每个客户端可见的字段数量。为每个客户拥有单独的DTO将帮助您选择应该可见的内容。

在此处输入图片说明