为什么数据传输对象(DTO)是反模式?

时间:2009-09-17 19:46:35

标签: java ejb dto anti-patterns data-transfer-objects

我最近听到人们说data transfer objects(DTO)是反模式

为什么呢?有哪些替代方案?

11 个答案:

答案 0 :(得分:121)

有些项目的所有数据都是两次。一旦作为域对象,一次作为数据传输对象。

这种重复成本很高,因此架构需要从这种分离中获得巨大收益才值得。

答案 1 :(得分:117)

DTO不是反模式。当您通过网络发送一些数据(例如,通过Ajax调用中的网页)时,您希望通过仅发送目标将使用的数据来确保节省带宽。此外,表示层通常可以方便地使数据的格式与本机业务对象略有不同。

我知道这是一个面向Java的问题,但在.NET语言中,匿名类型,序列化和LINQ允许在运行中构建DTO,这减少了使用它们的设置和开销。

答案 2 :(得分:22)

DTO an AntiPattern in EJB 3.0说:

  

实体的重量级特性   EJB规范之前的Bean   EJB 3.0导致了使用   设计模式,如数据传输   对象(DTO)。 DTO成为了   轻量级对象(应该有   是实体豆本身   第一个地方),用于发送   跨层的数据......现在是EJB 3.0   spec使Entity bean模型相同   作为普通的旧Java对象(PO​​JO)。同   这个新的POJO模型,你不会   需要为每个人创建一个DTO   实体或一组实体......如果   您想发送EJB 3.0实体   整个层面使他们只是   实现java.io.Serialiazable

答案 3 :(得分:17)

我不认为DTO本身就是一种反模式,但是有一些与使用DTO相关的反模式。 Bill Dudney以DTO爆炸为例:

http://www.softwaresummit.com/2003/speakers/DudneyJ2EEAntiPatterns.pdf

此处提到的DTO也有许多滥用行为:

http://anirudhvyas.com/root/2008/04/19/abuses-of-dto-pattern-in-java-world/

它们起源于三层系统(通常使用EJB作为技术)作为在层之间传递数据的手段。基于Spring等框架的大多数现代Java系统在单层中使用POJO作为域对象(通常用JPA等注释......)采用另一种简化视图......这里不需要使用DTO。

答案 4 :(得分:13)

纯粹主义者会说DTO是反模式的,因为对象变成数据表表示而不是真正的域对象。

答案 5 :(得分:7)

有些人认为DTO是一种反模式,因为它们可能存在滥用行为。它们经常在它们不应该/不需要的时候使用。

This article模糊地描述了一些滥用行为。

答案 6 :(得分:6)

如果您正在构建分布式系统,那么DTO肯定不是反模式。不是每个人都会在这个意义上发展,但如果你有一个(例如)Open Social应用程序都运行JavaScript。

它会向您的API发布大量数据。然后将其反序列化为某种形式的对象,通常是DTO / Request对象。然后可以对其进行验证,以确保在转换为模型对象之前输入的数据是正确的。

在我看来,它被视为一种反模式,因为它被误用了。如果您不构建分布式系统,则可能不需要它们。

答案 7 :(得分:3)

Data Transfer Object的意图是存储来自不同来源的数据,然后立即将其传输到数据库(或Remote Facade)。

然而, DTO模式违反了Single Responsibility Principle ,因为DTO不仅存储数据,还将数据传输到数据库/外观。

将数据对象与业务对象分开的需要不是反模式,因为无论如何它可能都需要separate the database layer

您应该使用聚合和存储库模式来代替DTO,这些模式分隔对象集合(Aggregate)和数据传输(Repository)。

要传输一组对象,您可以使用Unit Of Work模式,该模式包含一组存储库和事务上下文;为了在事务中单独转移聚合中的每个对象。

答案 8 :(得分:3)

当您让所有域对象加载关联对象时,DTO成为必需品,而不是ANTI-PATTERN。

如果您不制作DTO,则会有从业务层到客户/网络层的不必要转移的对象。

限制此情况的开销,而不是转移DTO。

答案 9 :(得分:1)

问题不应该是“为什么”,而应该是“ 何时”。

绝对是反模式,只有使用它的结果是更高的成本-运行时或维护。我从事的项目具有与数据库实体类相同的数百个DTO。每次您要添加一个字段时,您的广告都会向IDTO添加四倍的ID-到DTO,到实体,从DTO到领域类或实体的转换,逆向转换... ...您忘记了获得的一些位置和数据不一致的。

当您确实需要域类的不同表示形式时,这不是反模式-更平坦,更丰富,更狭窄,...

我个人从域类开始,并在正确的位置进行适当的检查,然后将其传递。我可以注释和/或添加一些“帮助程序”类,以进行映射,数据库,序列化格式(如JSON或XML)……如果需要,我总是可以将一个类拆分为两个。

这是关于您的观点的-我更喜欢将域对象视为扮演各种角色的单个对象,而不是彼此创建的多个对象。如果对象唯一的角色是传输数据,则为DTO。

答案 10 :(得分:0)

我认为,如果您将所有远程对象实现为DTO,那么人们就意味着它可能是一种反模式。 DTO只是一组属性,如果您有大对象,即使您不需要或使用它们,也总是会传输所有属性。在后一种情况下,更喜欢使用代理模式。