为什么数据传输对象 (DTO) 是反模式?
我最近无意中听到人们说数据传输对象 (DTO) 是一种反-模式。
为什么?有哪些替代方案?
I've recently overheard people saying that data transfer objects (DTOs) are an anti-pattern.
Why? What are the alternatives?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
有些项目的所有数据都有两次。一次作为域对象,一次作为数据传输对象。
这种重复会产生巨大的成本,因此架构需要从这种分离中获得巨大的好处才值得。
Some projects have all data twice. Once as domain objects, and once as data transfer objects.
This duplication has a huge cost, so the architecture needs to get a huge benefit from this separation to be worth it.
DTO 不是反模式。当您通过网络发送一些数据(例如,通过 Ajax 调用发送到网页)时,您需要确保仅发送目标将使用的数据来节省带宽。此外,对于表示层来说,通常使用与本机业务对象略有不同的格式的数据会很方便。
我知道这是一个面向 Java 的问题,但在 .NET 语言中,匿名类型、序列化和 LINQ 允许动态构建 DTO,从而减少了使用它们的设置和开销。
DTOs are not an anti-pattern. When you're sending some data across the wire (say, to a web page in an Ajax call), you want to be sure that you conserve bandwidth by only sending data that the destination will use. Also, often it is convenient for the presentation layer to have the data in a slightly different format than a native business object.
I know this is a Java-oriented question, but in .NET languages anonymous types, serialization, and LINQ allow DTOs to be constructed on-the-fly, which reduces the setup and overhead of using them.
“DTO an AntiPattern in EJB 3.0”(原始链接目前离线)说:
"DTO an AntiPattern in EJB 3.0" (original link currently offline) says:
OO 纯粹主义者会说 DTO 是反模式,因为对象变成了数据表表示而不是真正的域对象。
OO purists would say that DTO is anti-pattern because objects become data table representations instead of real domain objects.
我不认为 DTO 本身是一种反模式,但存在与 DTO 的使用相关的反模式。 Bill Dudney 以 DTO 爆炸为例:
Internet Archive 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。
I don't think DTOs are an anti-pattern per se, but there are antipatterns associated with the use of DTOs. Bill Dudney refers to DTO explosion as an example:
Internet Archive http://www.softwaresummit.com/2003/speakers/DudneyJ2EEAntiPatterns.pdf
There are also a number of abuses of DTOs mentioned here:
Internet Archive http://anirudhvyas.com/root/2008/04/19/abuses-of-dto-pattern-in-java-world/
They originated because of three tier systems (typically using EJB as technology) as a means to pass data between tiers. Most modern day Java systems based on frameworks such as Spring take an alternative simplified view using POJOs as domain objects (often annotated with JPA etc...) in a single tier... The use of DTOs here is unnecessary.
问题不应该是“为什么”,而是“何时”。
毫无疑问,它是一种反模式,因为使用它的唯一结果是更高的成本 - 运行时或维护。我从事的项目有数百个与数据库实体类相同的 DTO。每次你想添加一个字段时,你都必须添加 id 四次 - 到 DTO、到实体、从 DTO 到域类或实体的转换、反向转换,......你忘记了一些地方和数据不一致。
当您确实需要域类的不同表示时,这不是反模式 - 更平坦、更丰富……就
我个人而言,我从域类开始并将其传递,并在正确的位置进行适当的检查。我可以注释和/或添加一些“帮助器”类来映射到数据库、序列化格式(如 JSON 或 XML)...如果我觉得有需要,我总是可以将一个类分成两个。
这是关于你的观点 - 我更喜欢将域对象视为扮演各种角色的单个对象,而不是彼此创建的多个对象。如果对象的唯一作用是传输数据,那么它就是 DTO。
The question should not be "why", but "when".
Definitively it's an anti-pattern when the only result of using it is higher cost - run-time or maintenance. I worked on projects having hundreds of DTOs identical to database entity classes. Each time you wanted to add a single field you had to add id like four times - to DTO, to entity, to conversion from DTO to domain classes or entities, the inverse conversion, ... You forgot some of the places and data got inconsistent.
It's not an anti-pattern when you really need different representation of domain classes - flatter, richer, ...
Personally, I start with a domain class and pass it around, with proper checks at the right places. I can annotate and/or add some "helper" classes to make mappings to database, to serialization formats like JSON or XML ... I can always split a class to two if I feel the need.
It's about your point of view - I prefer to look at a domain object as a single object playing various roles, instead of multiple objects created from each other. If the only role of an object is to transport data, then it's DTO.
有些人认为 DTO 是一种反模式,因为它们可能被滥用。它们经常在不应该/不需要的时候使用。
这篇文章模糊地描述了一些滥用行为。
Some consider DTOs an anti-pattern due to their possible abuses. They're often used when they shouldn't be/don't need to be.
This article vaguely describes some abuses.
如果您正在构建分布式系统,那么 DTO 肯定不是反模式。并不是每个人都会在这种意义上进行开发,但如果你有一个(例如)开放社交应用程序,所有应用程序都运行 JavaScript。
它将向您的 API 发送大量数据。然后将其反序列化为某种形式的对象,通常是 DTO/Request 对象。然后可以对其进行验证,以确保输入的数据在转换为模型对象之前正确无误。
在我看来,它被视为一种反模式,因为它被滥用了。如果您不构建分布式系统,那么您很可能不需要它们。
If you're building a distributed system, then DTOs are certainly not an anti pattern. Not everyone will develop in that sense, but if you have a (for example) Open Social app all running off JavaScript.
It will post a load of data to your API. This is then deserialized into some form of object, typically a DTO/Request object. This can then be validated to ensure the data entered is correct before being converted into a model object.
In my opinion, it's seen as an anti-pattern because it's mis-used. If you're not build a distributed system, chances are you don't need them.
当您让所有域对象都急切地加载关联对象时,DTO 就成为必需品,而不是反模式。
如果您不创建 DTO,则会将不必要的对象从业务层传输到客户端/Web 层。
为了限制这种情况下的开销,最好转移 DTO。
DTO becomes a necessity and not an ANTI-PATTERN when you have all your domain objects load associated objects EAGERly.
If you don't make DTOs, you will have unnecessary transferred objects from your business layer to your client/web layer.
To limit overhead for this case, rather transfer DTOs.
我认为人们的意思是,如果将所有远程对象实现为 DTO,这可能是一种反模式。 DTO 只是一组属性,如果您有大对象,即使您不需要或不使用它们,您也始终会传输所有属性。在后一种情况下更喜欢使用代理模式。
I think the people mean it could be an anti-pattern if you implement all remote objects as DTOs. A DTO is merely just a set of attributes and if you have big objects you would always transfer all the attributes even if you do not need or use them. In the latter case prefer using a Proxy pattern.
数据传输对象的目的是存储来自不同来源的数据,然后将其传输到立即数据库(或远程外观)。
但是,DTO 模式违反了单一职责原则,因为 DTO 不仅存储数据,而且还将数据从数据库/外观传输到数据库/外观。
将数据对象与业务对象分开的需要不是反模式,因为可能需要 无论如何,分离数据库层。
您应该使用聚合和存储库模式而不是 DTO,它将对象集合分开(聚合 )和数据传输(存储库)。
要传输一组对象,您可以使用 工作单元 模式,该模式包含一组存储库和事务上下文;以便在交易中单独传输聚合中的每个对象。
The intention of a Data Transfer Object is to store data from different sources and then transfer it into a database (or Remote Facade) at once.
However, the DTO pattern violates the Single Responsibility Principle, since the DTO not only stores data, but also transfers it from or to the database/facade.
The need to separate data objects from business objects is not an antipattern, since it is probably required to separate the database layer anyway.
Instead of DTOs you should use the Aggregate and Repository Patterns, which separates the collection of objects (Aggregate) and the data transfer (Repository).
To transfer a group of objects you can use the Unit Of Work pattern, that holds a set of Repositories and a transaction context; in order to transfer each object in the aggregate separately within the transaction.
需要 DTO,因为域实体实例必须始终有效。因为大多数时候您需要对实体实例化进行验证,也就是说,在域层中,您无法实例化无效的域实体并稍后对其进行验证。简而言之:域实体必须始终有效。
另一件事是 dto 既可以是输入也可以是输出。作为输入,它可以防止过度发布漏洞,即当用户传递不允许执行的额外字段时,作为输出,它会隐藏您不想显示的字段。
DTO are needed cause an domain entity instance must always me valid. Cause most of the time you will need to do validation on entity instantiation, that is, in domain layer, you can`t instantiate an invalid domain entity and to validate it later. In short: an domain entity must always be valid.
Other thing is that dto can be both input and output. As input its prevent over posting vulnerability which is when user pass extra fields that is not allowed to do and as output it hides fields that you dont want to show.