DTO(数据传输对象)模式

article/2025/9/22 11:41:07

0. 写在前面

首先,这是一篇翻译文章,个人建议你可以阅读英文原文Baeldung: The DTO Pattern (Data Transfer Object),因为个人水平,很多地方翻译的不通顺和晦涩,如果你选择继续往下看,请不要高估了我的英文水平。当然,你也可以对比原文来看。

1. 概览

在这篇教程中,我们将讨论 DTO 模式,它是什么,怎样以及何时使用它们。在最后,希望我们知道如何正确地使用它。

2. DTO模式

DTO 或者说数据传输对象(Data Transfer Objects)是在处理方法中携带数据的对象,**目的是减少方法调用的次数。**Martin Fowler 在他的书Patterns of Enterprise Application Architecture中第一次提出该模式。他解释说该模式的主要目的是通过将一次单一调用的多个参数分批来减少到服务器的往返次数。因而在这样的远程操作中降低网络开销。该实践的其它好处是序列化的逻辑(转换对象结构和数据为一种能被存储和传输的指定格式的机制)的封装。它提供了在序列化细微差别中一个单一改变点。它也解耦了表示层的领域模型,允许它们独自改变。

3. 怎样使用它

DTOs 一般被创建为 POJOs。它们是平整的数据结构,不包含业务逻辑,仅仅有存储、访问和最终关联序列化或解析的方法。数据从领域模型映射为 DTO,一般通过在表示层或门面层的 mapper 组件。下方的图片说明了组件间的交互:
表示层

4. 何时使用它

正如它的定义中提到的,DTO 在带有远程调用的系统中出现,因为它帮助减少了调用的次数。当领域模型有多种不同对象组成,并且表示层模型甚至一次需要它们的全部数据时,DTO 也能帮忙减少在客户端和服务器间的往返。使用 DTO,我们能从领域模型中构建不同的视角,允许我们创造相同域但优化它们为不影响域设计的客户端的需求的其它表示。这样的灵活性是一个解决复杂问题的强力工具。

5. 使用事例

为了展示这个模式的实现,我们将使用一个有两个主要领域模型的简单应用。在这个事例中,UserRole,为了专注于该模式,让我们看两个功能性的例子,获取用户和创建新用户。

5.1 DTO vs. Domain

下方定义了这两个模型:

public class User {private String id;private String name;private String password;private List<Role> roles;public User(String name, String password, List<Role> roles) {this.name = Objects.requireNonNull(name);this.password = this.encrypt(password);this.roles = Objects.requireNonNull(roles);}// Getters and SettersString encrypt(String password) {// encryption logic}
}
public class Role {private String id;private String name;// Constructors, getters and setters
}

现在,让我们看看 DTO,以便于和领域模型比较。此时,重点关注的是 DTO 表示发送自发送至 API 客户端的模型。因此,这些小差异要么是为了打包请求发送到服务器,要么是优化客户端的响应。

public class UserDTO {private String name;private List<String> roles;// standard getters and setters
}

上方的 DTO 仅仅提供了到客户端的相关信息,隐藏了密码,比如出于安全原因。接下来的对象组织了全部必要的数据在一次请求中来创建一个用户和发送它到服务器。并且之前提到的,这优化了 API 的交互。看看下面的代码:

public class UserCreationDTO {private String name;private String password;private List<String> roles;// standard getters and setters
}

5.2 连接两端

接下来,绑定两类的 layer 使用一个 mapper 组件去传递从一端到另一端,反之也是。这通常发生在表示层,就像下面展示的:

@RestController
@RequestMapping("/users")
class UserController {private UserService userService;private RoleService roleService;private Mapper mapper;// Constructor@GetMapping@ResponseBodypublic List<UserDTO> getUsers() {return userService.getAll().stream().map(mapper::toDto).collect(toList());}@PostMapping@ResponseBodypublic UserIdDTO create(@RequestBody UserCreationDTO userDTO) {User user = mapper.toUser(userDTO);userDTO.getRoles().stream().map(role -> roleService.getOrCreate(role)).forEach(user::addRole);userService.save(user);return new UserIdDTO(user.getId());}}

最后,我们创建 Mapper 组件来转换数据确保 DTO 和领域模型都不必知道对方:

@Component
class Mapper {public UserDTO toDto(User user) {String name = user.getName();List<String> roles = user.getRoles().stream().map(Role::getName).collect(toList());return new UserDTO(name, roles);}public User toUser(UserCreationDTO userDTO) {return new User(userDTO.getName(), userDTO.getPassword(), new ArrayList<>());}
}

6. 常见错误

虽然 DTO 模式是一种相当简单的设计模式,但是一些错误在实现了这一技巧的应用中被频繁地发现。

第一个是对每一个情形创建不同的 DTO。这将会增加我们需要维护的类和 mapper 们的数量。尝试去保持它们简洁,并且尝试对添加一个新的 DTO 和重用现有的 DTO 做一个权衡。

反向也是有效的。避免对于许多场景使用一个结构简单的类(个人理解:将多个 DO 塞进一个 DTO),这种实践将会导致 DTO 中的许多属性很少被用到,此时,DTO 就像是一个大合同。

其它的常见错误是增加业务逻辑到 DTO 里。这不应该发生。这个模式的目的是优化数据传输和通信协议的结构。因此,全部的业务逻辑都应该在 domain 层。

最后,我们是称作 LocalDTO 的使用,它表示 DTO 传递数据跨过多个域。再一次出现的问题是维护全部映射的成本。支持这种方法的最常见的论点之一是域模型的封装。但实际上,这里的问题是领域模型和持久化模型耦合在一起。通过解耦它们,暴露领域模型的风险基本消失。不过,其它的模式遇到了类似的结果,但是它们通常被使用在更复杂的场景,如 CQRS、Data Mappers、CommandQuerySeparation 等。

7. 结论

在这篇文章中,我们看到了 DTO 模式的定义和它存在的理由,以及怎样去实现它。我们也看到了实现它时一些常见的关联的错误和避免这些错误的方式。你可以在原文中找到这个例子的源码地址。


http://chatgpt.dhexx.cn/article/GxInDvcq.shtml

相关文章

DTO介绍

先看看这张图&#xff0c;dto所处位置&#xff0c;主要是用于业务逻辑层service和表示层servlet之间的数据传输 什么是DTO(Data Transfer Object)数据传输对象&#xff1f; DTO是一个比较特殊的对象&#xff0c;他有两种存在形式&#xff1a; 在后端&#xff0c;他的存在形式…

阿里巴巴Java开发手册中的DO、DTO、BO、AO、VO、POJO定义

常用文件夹分层&#xff1a; pojo vo &#xff08;与前端交互的所有对象&#xff0c;包括接参和返回&#xff09;query &#xff08;查询的筛选条件&#xff0c;前端传参和后端内部传参通用&#xff09;entity &#xff08;数据库表基础对象&#xff09;dto&#xff08;后端内…

R下载与安装详细指南

一、登陆www.r-project.org进入R官网 二、点击左侧CRAN或右侧的download R 三、在China选项&#xff0c;随机点击一个镜像 四、R语言可以在Linux、MAC OS和Windows上运行&#xff0c;根据个人的操作系统选择需要下载的镜像 五、点击下载、运行、选择中文版本 六、安装过程 …

Rstudio下载太慢安装报错???

目录 00引言1、正文1.1踩过的坑1.1.1下载慢1.1.2安装报错 1.2经验方法1.3结果 00引言 因为Rmarkdown的原因&#xff0c;最近开始不想使用原生态的R编译器了。开始升级Rstudio了。但是从下载到安装的坑确实不少。 1、正文 1.1踩过的坑 1.1.1下载慢 这是下载了一晚上的结果&…

R语言下载气象数据

近来气象数据共享网的账户到期&#xff0c;失去日序列数据的下载权限。总结了以下R语言气象数据的下载包。尚未亲自尝试&#xff0c;具体各包的适用情况诸君请自行研究。 package一览 下列所有包的来源均属于 rOpenSci 项目. 1. GSODTools 2. GSOD 3. rnoaa 4. bomrang 5. r…

Linux+conda+R+Rstudio下载安装环境全方面配置

很多小伙伴不习惯在R中用到conda环境&#xff0c;其实这可能是因为你还没有使用到对环境有更高要求的包。 假如我们想安装R包A&#xff0c;它要求的R版本是4.3.0&#xff0c;但是你现在R版本是4.2.0&#xff0c;并且你其他的算法包都是根据4.2.0所创建的&#xff0c;那么就会造…

R语言使用教程(三)——Rstudio添加镜像源(加快包的下载)

文章目录 Windows系统R语言使用教程&#xff08;三&#xff09;——Rstudio添加镜像源(加快包的下载)打开rstudio --> Tools --> Global Options -->Packages --> add -->输入--> Change --> 选择离自己最近的源 --> Apply --> OK参考链接 Windows系…

【数据分析入门】R语言下载与R包新旧设备转移

一、R语言下载 https://cran.rstudio.com/ 二、Rstudio下载 https://www.rstudio.com/products/rstudio/download/#download Rstudio是R语言的集成开发环境 如果R语言是饭&#xff0c;Rstudio就是筷子 不用筷子也行&#xff0c;可以用手&#xff08;直接用R&#xff09; 但是…

R语言批量下载PubMed摘要

1&#xff0c;安装easyPubMed包&#xff1a; install.packages("easyPubMed")2&#xff0c;关键字搜索下载摘要信息 library(easyPubMed) query <- "GATK" #以关键字“GATK”为例 file_name <- "GATK" #保存结果的输出文件的文件名前缀…

R或RStudio下载包时出错解决方案

当我们想要在R&RStudio中下载包时可能会出现如下类似错误 在如下目录中的Rprofile.site文件中对应位置增加一条代码即可&#xff1a; options(download.file.method"libcurl") 修改好后&#xff0c;再次下载即可成功&#xff01;

R语言源代码下载

吐槽&#xff1a;老师说让我去找开源代码&#xff0c;不要用别人做好的软件。 经过调研&#xff0c;有两个可以用的开源软件&#xff0c;一个是bibliometrix&#xff0c;一个是SciMAT。 软件都没用过就算了&#xff0c;学一学就行&#xff0c;可是这些软件只支持英文文献&#…

R3.6.3下载 Rstudio下载及安装,网盘链接永久有效

链接&#xff1a;https://pan.baidu.com/s/1ab1JdmzKDAbDuUv76K3g1Q 提取码&#xff1a;pzkj 永久有效&#xff0c;收藏点赞拿走 记得软件安装路径一定不要有中文、空格&#xff0c;默认安装就没什么问题&#xff0c;其他问题可以联系文末微信号&#xff0c;24小时解答。 参考…

R和Rstudio 下载安装

R下载地址 1.选择自己电脑系统 2.点击base 3.选择合适版本下载 Rstudio下载地址 点击右上角 DOWNLOAD 点击 Free下 DOWNLOAD 选择合适的下载即可 机械安装即可&#xff08;默认安装C盘&#xff0c;可自行更改安装路径&#xff09; 在电脑开始页可看见&#xff0c;如图

R和RStudio下载安装详细步骤

相关文章&#xff1a; r语言基础知识 r语言习题和参考答案 r语言数据分析案例 还有很多相关文章都在我的专栏里面&#xff1a;R语言专栏 本文介绍R和RStudio的下载安装&#xff08;Windows系统&#xff09;&#xff0c;步骤十分详细&#xff08;按照我截图的顺序来即可&#x…

第一课 R语言下载和安装

一、什么是 R 语言 R 编程语言被广泛应用在统计科学和商业领域。在各种编程语言排名中 R 语言的排名 都很靠前。它是一款集成了数据操作、统计&#xff0c;以及可视化功能的优秀开源软件。免费&#xff0c;开源 是 R 重要的特点。 二、什么是 RStudio RStudio 是用亍 R 编…

R语言下载GEOquery包

一开始我用的是R语言常用的下载方式 install.packages(GEOquery) 结果报错了。 然后&#xff0c;我在网上查找资料&#xff0c;看到这个视频 如何在R上下载GEOquery包_哔哩哔哩_bilibili 首先&#xff0c;确认有BiocManager包&#xff0c;没有的话就下载 if(!requireNames…

RStudio 下载R包的几种方法

1. 使用RStudio自带的安装方法&#xff0c;右侧找到Packages&#xff0c;点击Install&#xff0c;然后输入package_name即可 2.使用CRAN&#xff0c;repos后面的镜像地址可以更改&#xff0c;一般使用的是这个清华的镜像。 #一般使用第一行命令进行安装&#xff0c;如果不成功…

R语言——RStudio下载R包时总是下载不成功?解决方案

RStudio下载R包出现Warning in install.packages的情况 原因是&#xff1a;由于RStudio的源是Global&#xff0c;所以在使用install命令去安装包的时候可能会出现数据部分丢失的情况。 解决方法&#xff1a;换源 在工具栏找到Tools->Global Options 在右边的栏目里找到Pack…

Linux简单了解入门学习一

1. 学习Linux之前先认识Unix l Unix是一个强大的多用户、多任务操作系统。 l 于1969年在AT&T的贝尔实验室开发。 l UNIX的商标权由国际开放标准组织(The Open Group)所拥有。 l UNIX操作系统是商业版,需要收费,价格比Microsoft Windows正版要贵一些。 2. Linux l…

(一) Linux入门概述

系列文章目录 &#xff08;一&#xff09; Linux入门概述 &#xff08;二&#xff09; Linux环境搭建 &#xff08;三&#xff09; Linux常用命令 &#xff08;四&#xff09; 软件安装与部署 文章目录 系列文章目录前言Linux概述 前言 Linux和Windows一样是一个操作系统软件&…