什么是数据传输对象?


Answers:


221

数据传输对象是用于封装数据并将其从应用程序的一个子系统发送到另一个子系统的对象。

NTO应用程序中的服务层最常使用DTO在自身和UI层之间传输数据。这样做的主要好处是,它减少了分布式应用程序中需要通过网络发送的数据量。他们还在MVC模式中建立了出色的模型。

DTO的另一个用途是封装方法调用的参数。如果某个方法采用的参数超过4个或5个,则这将很有用。

使用DTO模式时,您还将使用DTO汇编程序。汇编程序用于从域对象创建DTO,反之亦然。

从域对象到DTO的转换再转换回来可能是一个昂贵的过程。如果您不创建分布式应用程序,那么该模式可能不会带来任何好处,正如Martin Fowler在此处解释的那样


7
“ DTO用MVC模式创建了出色的模型”-但是模型不应该包含对象的所有数据,而DTO不能用部分数据进行优化吗?如果我有模型A,并且需要将其传递给两个子系统,是否会有A_DTO_1和A_DTO_2以及各自的相关字段?“ DTO可以封装方法调用的参数”->因此,包装参数的每个类都是DTO,即使它不是分布式系统也是如此?MVC中的模型不是域对象吗?
Yaron Naveh,2009年

2
在回答您的第一个问题时,我认为不是在谈论同一件事。MVC中的模型不一定必须是您的域模型中的类。话虽如此,这很可能是。使用DTO可以清除所有不必要的内容。仅取决于您要使用的体系结构。我不确定如何回答您的第二个问题。无论是跨线传输还是跨线传输,它仍然是封装了在(子系统)系统之间传输的一堆数据的对象,所以我认为这是DTO。
本尼·哈雷特

11
“ DTO的另一个用途可以是封装方法调用的参数。如果一个方法需要4个或5个以上的参数,这将很有用。” 这实际上是一种称为Poltergeist或Gypsy Wagon类的反模式。如果您的方法需要4个参数,则给它4个参数,不要仅仅为了将对象移入方法或类而创建类。
Wix 2010年

2
@Wix,好点。但是我认为如果它在语义上是正确的(例如,如果您传递带有属性的设置类而不是将属性本身作为值),这是可以的。为了传递单个对象,您不应该做的是将所有参数都放入,因为它们很可能是不相关的,并且会在以后引起恶梦。
Aram Kocharyan 2012年

3
DTO不应用于封装方法调用的参数(这将使它们成为LocalDTO),它们是在远程接口的上下文中引入的:martinfowler.com/bliki/LocalDTO.html
Rui

28

DTO的定义可以在Martin Fowler的站点上找到。DTO用于将参数传递给方法并作为返回类型。很多人在UI中使用它们,但其他人则从其中膨胀域对象。


22

DTO是一个愚蠢的对象-它仅保留属性并具有getter和setter,但没有其他任何有意义的逻辑(可能是compare()或equals()实现)。

通常,MVC中的模型类(此处为.net MVC)是DTO或DTO的集合/集合。


3
您所描述的是LocalDTO:martinfowler.com/bliki/LocalDTO.html

3
使用DTO之类的方法很有用的一种情况是,您的表示层模型与基础域模型之间存在重大不匹配。在这种情况下,使特定于演示文稿的外观/网关从域模型进行映射并呈现一个便于演示的界面是有意义的。
阿弥陀佛(Amitābha)

14

通常,值对象应该是不可变的。就像Java中的IntegerString对象一样。我们可以使用它们在软件层之间传输数据。如果软件层或服务在不同的远程节点(例如微服务环境或旧版Java Enterprise App)中运行。我们必须几乎完全复制两个类。这是我们遇到DTO的地方。

|-----------|                                                   |--------------|
| SERVICE 1 |--> Credentials DTO >--------> Credentials DTO >-- | AUTH SERVICE |
|-----------|                                                   |--------------|

在旧版Java Enterprise Systems中,DTO可以包含各种EJB东西。

我不知道这是否是最佳实践,但我个人在Spring MVC / Boot项目中使用Value Objects像这样:

        |------------|         |------------------|                             |------------|
-> Form |            | -> Form |                  | -> Entity                   |            |
        | Controller |         | Service / Facade |                             | Repository |
<- View |            | <- View |                  | <- Entity / Projection View |            |
        |------------|         |------------------|                             |------------|

控制器层不知道实体是什么。它与FormView Value Objects通信。表单对象具有JSR 303验证注释(例如@NotNull),而视图值对象具有用于自定义序列化的Jackson注释。(例如@JsonIgnore)

服务层通过使用实体对象与存储库层进行通信。实体对象上具有JPA / Hibernate / Spring Data批注。每一层仅与下层通信。由于循环/循环依赖性,禁止层间通信。

User Service ----> XX CANNOT CALL XX ----> Order Service

一些ORM框架具有通过使用其他接口或类进行投影的能力。因此,存储库可以直接返回View对象。在那里,您不需要其他转换。

例如,这是我们的用户实体:

@Entity
public final class User {
    private String id;
    private String firstname;
    private String lastname;
    private String phone;
    private String fax;
    private String address;
    // Accessors ...
}

但是,您应该返回仅包含id,firstname,lastname的用户分页列表。然后,您可以为ORM投影创建一个View Value Object。

public final class UserListItemView {
    private String id;
    private String firstname;
    private String lastname;
    // Accessors ...
}

您可以轻松地从存储库层获取分页结果。多亏了spring,您也可以只使用接口进行投影。

List<UserListItemView> find(Pageable pageable);

别担心其他转换操作BeanUtils.copy方法效果很好。


11
  1. 对我来说,什么是DTO的最佳答案是DTO简单对象,不应包含任何需要测试的业务逻辑或方法实现
  2. 通常,您的模型(使用MVC模式)是智能模型,并且它们可以包含很多/某些方法,专门针对该模型执行一些不同的操作(不是业务逻辑,应该在控制器处)。但是,当您传输数据(例如,从某个地方调用REST(GET// POST无论如何)终结点,或使用SOA使用网络服务等)时,您不希望使用不需要执行以下代码的大型对象来传输数据端点将消耗数据,并减慢传输速度。

为什么要在控制器中使用业务逻辑?
AlexioVay

6

使用MVC,数据传输对象通常用于将域模型映射到较简单的对象,这些对象最终将由视图显示。

维基百科

数据传输对象(DTO),以前称为值对象或VO,是一种设计模式,用于在软件应用程序子系统之间传输数据。DTO通常与数据访问对象结合使用,以从数据库中检索数据。


3
值对象不是DTO
coderpc

0

数据传输对象(DTO)描述“在进程之间携带数据的对象”(维基百科)或“用于封装数据并将其从应用程序的一个子系统发送到另一个子系统的对象”(堆栈溢出答案)。


0

国防部

DTO是硬编码的数据模型。它仅解决了对由硬编码的生产过程处理的数据记录建模的问题,在该过程中,所有字段在编译时都是已知的,因此可以通过强类型化的属性进行访问。

相反,动态模型或“属性袋”解决了在运行时创建生产过程时对数据记录建模的问题。

Cvar

可以使用字段或属性对DTO进行建模,但是有人发明了一个非常有用的数据容器,称为Cvar。它是对值的引用。当使用我称为参考属性的DTO建模时,可以将模块配置为共享堆内存,从而在其上协同工作。这完全消除了代码中的参数传递和O2O通信。换句话说,具有参考特性的DTO允许代码实现零耦合

    class Cvar { ... }

    class Cvar<T> : Cvar
    {
        public T Value { get; set; }
    }

    class MyDTO
    {
        public Cvar<int> X { get; set; }
        public Cvar<int> Y { get; set; }
        public Cvar<string> mutableString { get; set; } // >;)
    }

资料来源:http : //www.powersemantics.com/

动态DTO是动态软件的必要组件。要实例化动态过程,一个编译器步骤是将脚本中的每台计算机绑定到脚本定义的参考属性。通过将Cvar添加到集合中来构建动态DTO。

    // a dynamic DTO
    class CvarRegistry : Dictionary<string, Cvar> { }

争论

注意:由于Wix将使用DTO来组织参数标记为“反模式”,因此,我将给出权威意见。

    return View(model);  // MVC disagrees

我的协作架构取代了设计模式。请参阅我的网络文章。

参数可立即控制堆栈框架机器。如果使用连续控制,因此不需要立即控制,则模块不需要参数。我的架构没有。当参数是值类型时,机器的内部配置(方法)会增加复杂性,但也会增加值(性能)。但是,引用类型参数会使使用方导致缓存未命中,但无论如何都会从堆中获取值-因此,只需使用引用属性配置使用方即可。机械工程的事实:对参数的依赖是一种预优化,因为加工(制造零件)本身就是浪费。有关更多信息,请参阅我的W文章。http://www.powersemantics.com/w.html

如果Fowler和公司曾经了解过任何其他架构,他们可能会意识到DTO在分布式架构之外的好处。程序员只知道分布式系统。集成协作系统(又名生产aka制造)是我必须声明的自己的体系结构,因为我是第一个以这种方式编写代码的人。

有些人将DTO视为贫血领域模型,这意味着DTO缺乏功能,但是这假定对象必须拥有与之交互的数据。然后,此概念模型迫使您在对象之间传递数据,这是用于分布式处理的模型。但是,在生产线上,每个步骤都可以访问最终产品并对其进行更改,而无需拥有或控制它。那就是分布式处理与集成处理之间的区别。制造业将产品与运营和物流分开。

作为一群无用的上班族,他们在不保持电子邮件追踪的情况下通过电子邮件相互发送电子邮件的过程没有建模方面的内在错误,除了它在处理物流和退货问题时造成的所有额外工作和麻烦。正确建模的分布式过程会将文档(活动路由)附加到产品上,以描述产品来自何处以及将要进行的操作。活动路由是流程源路由的副本,该副本是在流程开始之前编写的。如果发生故障或其他紧急更改,则修改活动路由以包括将发送到的操作步骤。这样就解决了所有投入生产的劳动。

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.