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

nto*_*end 125 java ejb anti-patterns data-transfer-objects dto

我最近听到人们说数据传输对象(DTO)是一种反模式.

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

KLE*_*KLE 130

有些项目有两次所有数据.一旦作为域对象,一次作为数据传输对象.

这种复制具有巨大的成本,因此架构需要从这种分离中获得巨大的好处才值得.

  • +1.两次?只有你很幸运:-)将域实体复制为DTO的项目也往往具有几乎相同但又如此微妙的不同UI豆来补充它们.那是3.如果,上帝禁止,有某种远程处理(web服务/ xml-rpc /无论如何),你可以很容易地达到4或5. (66认同)
  • 我目前正在使用enterpricy 14层烤宽面条架构(不是KIDDING).我可以向你保证,主要用于数据传输的大约11层不是免费的. (16认同)
  • 此外,虽然我在使用愚蠢的设计时非常喜欢代码生成器,但它们a)确定你开始做错了.b)他们不是免费的. (8认同)
  • 对不起,但这是不正确的,错误的答案得到了很高的评价并被接受了.首先,您可以使用反射来动态生成DTO.其次,您可以使用"根定义",例如在CASE系统或oAW中,并生成BO和DTO.第三,你可以使用XSD和JAXB来生成DTO并使用DTO作为BO的基础,或者你可以从XSD生成两者......无论如何,如果有人敢于从DB中新传取的EJB那么连接到客户端程序......在我工作的环境中,他的头很快会在银盘上...... (6认同)
  • 请详细说明"巨额费用".另外,说明为什么使用代码生成技术生成DTO类无法消除成本. (5认同)
  • 呵呵,代表来自活动和活动与年龄有关......我有时会在这里发帖,因为最近4个月左右.如果您的答案得到投票或接受,您也会得到代表......我主要是纠正错误.就像这个答案错误的提升一样.如果我得到代表,我不在乎. (3认同)
  • 只是遗憾的是接受的答案没有回答“有什么选择”部分 (3认同)
  • 让我们看看第一个成本是将它们从域对象转换为DataDto.然后将DataDto转换为WebDto(或UiDto),第二次成本.然后在路上,你必须添加一个字段.因此,您必须将字段添加到域和2 Dtos以及转换例程.由于WebDtos通常都是字符串,因此现在您必须对数字字段进行一些计算.所以现在你必须改变WebDto,它是转换程序.还有另一项费用.因此,您需要花费开发时间,调试时间以及转换开销. (2认同)
  • @AngelO'Sphere 对我来说,听起来你的治疗比疾病更糟糕。至少对于不太有创业精神的项目。当然,您可以使用一些样板生成器来获得更多样板,而且它通常运行良好,但是遇到任何问题,您损失的时间都会超过节省的时间。 (2认同)

Gab*_*art 123

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

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

  • @John,这是不对的.我一直这样做.序列化使用反射,它在匿名类型上运行良好.只需将其作为对象传递给序列化程序.一旦它被序列化(例如xml或json),你当然可以从一个方法返回它. (15认同)
  • 嗯,约翰,那是不对的.您可以将匿名类型序列化为JSON就好了.在MVC应用程序中尝试:返回Json(new {Foo ="Hi there!});我保证它的工作正常.或许比非匿名类型更好,因为匿名类型通常在对象图中没有循环,打破了JSON序列化程序. (8认同)
  • +1.除了带宽保护之外还有很多其他原因,你需要DTO.您是否允许(根据公司政策或法律)通过电汇发送每个字段?此外,在我们公司,我们的DAO非常复杂,因为它需要进行所有这些优化 - 在服务层工作,我很高兴他们使用DTO并且不要让我们担心Object X的关系到其他一些n到n表. (3认同)
  • 从这个意义上说,Json 序列化不是 DTO,因此不适用。那么当然,我上面的论点也适用,在某些时候,它们就不再值得了。 (2认同)
  • Gabe 是对的,当没有数据重复时,DTO 本身并不是反模式(但如果使用不正确,也可能是反模式!)。例如,BO可以将不同来源的数据聚合到DTO中。 (2认同)

aem*_*aem 24

DMP和EJB 3.0中的AntiPattern说:

EJB 3.0之前EJB规范中Entity Beans的重量级特性导致使用数据传输对象(DTO)等设计模式.DTO成为轻量级对象(它本身应该是实体bean本身),用于跨层发送数据......现在EJB 3.0规范使Entity bean模型与Plain old Java对象(PO​​JO)相同.使用这个新的POJO模型,您将不再需要为每个实体或一组实体创建DTO ...如果要跨层发送EJB 3.0实体,则只需实现java.io.Serialiazable

  • 当您在同一JVM中的方法之间在内存中传输对象时为True.当您实际在线路上进行序列化并希望控制序列化的深度和/或保留延迟加载时,情况并非如此. (5认同)

Jon*_*Jon 19

我不认为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是不必要的.

  • 当你在适当的环境中使用DTO时,你是完全正确的[一个好的模式](http://martinfowler.com/eaaCatalog/dataTransferObject.html),而不是反模式.你的第二个链接现在看来已经死了,但是我看到的最大的滥用是每个域对象都有一个相应的"DTO"用于数据库交互,它没有增加任何价值而且根本不是DTO! (2认同)

Dar*_*rov 18

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

  • 您还如何向前端公开 API 视图模型? (2认同)

Ben*_*n S 8

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

本文模糊地描述了一些滥用行为.


Bea*_*ler 8

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

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

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


jav*_*dev 5

当您让所有域对象都急切地加载关联对象时,DTO 成为必需品而不是反模式。

如果您不制作 DTO,您将有不必要的对象从您的业务层传输到您的客户端/Web 层。

为了限制这种情况的开销,不如转移 DTO。


Ros*_*atl 5

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

当使用它的唯一结果是更高的成本- 运行时间或维护时,它绝对是反模式。我从事过与数据库实体类相同的具有数百个 DTO 的项目。每次你想添加一个字段时,你都会添加四次 id - 到 DTO,到实体,从 DTO 到域类或实体的转换,逆转换,...​​...你忘记了一些地方和数据不一致。

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

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

这是关于您的观点 - 我更喜欢将域对象视为扮演各种角色的单个对象,而不是相互创建的多个对象。如果对象的唯一作用是传输数据,那么它就是 DTO。