DTO和VO的区别及使用场景详解

devtools/2024/11/25 7:05:17/

随着互联网的发展,前后端分离的开发模式越来越流行。在前后端数据交互过程中,为了保证数据的安全性和效率,通常会采用 DTOVO 来封装数据。本篇博客将详细介绍 DTOVO 的区别以及使用场景。 

大家可能会有个疑问,既然DTO是展示层与服务层之间传递数据的对象,为什么还需要一个VO呢?对!对于绝大部分的应用场景来说,DTOVO的属性值基本是一致的,而且他们通常都是POJO,因此没必要多此一举,但不要忘记这是实现层面的思维,对于设计层面来说,概念上还是应该存在VODTO,因为两者有着本质的区别,DTO代表服务层需要接收的数据和返回的数据,而VO代表展示层需要显示的数据。

用一个例子来说明可能会比较容易理解:例如服务层有一个getUser的方法返回一个系统用户,其中有一个属性是gender(性别),对于服务层来说,它只从语义上定义:1-男性,2-女性,0-未指定,而对于展示层来说,它可能需要用“帅哥”代表男性,用“美女”代表女性,用“秘密”代表未指定。说到这里,可能你还会反驳,在服务层直接就返回“帅哥美女”不就行了吗?

对于大部分应用来说,这不是问题,但设想一下,如果需求允许客户可以定制风格,而不同风格对于“性别”的表现方式不一样,又或者这个服务同时供多个客户端使用(不同门户),而不同的客户端对于表现层的要求有所不同,那么,问题就来了。再者,回到设计层面上分析,从职责单一原则来看,服务层只负责业务,与具体的表现形式无关,因此,它返回的DTO,不应该出现与表现形式的耦合。

一、什么是VO?什么是DTO

DTO(Data Transfer Object)和 VO(Value Object)都是一种设计模式,用于封装数据和提供服务。它们的主要区别在于:

  • VO(View Object):视图对象,专门用于前端展示层,专注于表示某个具体的值或对象的对象,包含业务逻辑;VO的作用是将一组数据以适合特定用户界面(UI)的形式封装起来,确保数据的呈现既符合设计要求也满足用户体验标准。
    • 例如我们有一个电子商务网站,其中产品详情页需要显示产品的名称、价格、库存、图片等信息。VO会将这些信息以最优化的方式组织起来,供前端展示。比如,前端可能需要将产品分类显示为“热销商品”、“新品推荐”或“特价优惠”,VO会根据不同的展示需求,以适当的形式提供数据。例如,将从后端接收到的“男性”标签在客户端1上显示为“帅哥”,而在客户端2上显示为“靓仔”。
  • DTO(Data Transfer Object):数据传输对象,侧重于传输数据的对象,不包含业务逻辑;主要在展示层与服务层之间充当媒介,负责数据的标准化传输,确保数据在不同系统或组件间的准确无误传递。
    • 例如当展示层需要向服务层请求数据时,例如查询“男性”类别的产品,它会将“男性”这一概念封装进DTO中,以标准化格式发送请求。服务层接收到这个DTO后,理解为需要查询“男性”类别相关的产品数据,处理后同样以DTO的形式返回,其中可能包括所有“男性”类别的产品信息。这样,无论前端如何展示(如“帅哥”或“靓仔”),后端只需处理统一的“男性”类别,实现了前后端的解耦。

两者的关系:

  • DTOVO一一对应时,DTO等于视图模型,与VO属性值一致
  • 当一个DTO需适配多个VO时,DTO不等于视图模型,与VO不等价

二、使用场景

DTO

✨优点:可以避免数据的重复查询和传输,提高程序的性能和效率。减少代码的复杂度和维护难度,方便代码的开发和维护。因为DTO可以封装业务逻辑和数据格式,减少数据处理的复杂度。,增加数据的安全性。
✨缺点:可能增加开发初期的工作量,尤其是在需要创建和维护多个DTO的情况下,同时过度使用可能引入不必要的复杂性。

VO

✨优点:精确适配前端展示需求,促进前后端解耦,提高代码质量和可读性,因为VO专注于展示层面,避免了业务逻辑的混杂。
✨缺点:在处理大量数据或高并发场景下可能会影响前端性能,而且在多团队协作环境下,对VO的管理和同步可能变得较为复杂。

  • 跨系统数据标准化传输:选DTO,确保数据的一致性和格式标准化,减少数据处理的复杂度。
  • 前后端数据交换与解耦:用DTO,它能匹配前端需求,促进数据交换。
  • 保护敏感信息:DTO可以在数据传输过程中过滤敏感信息,而VO可以在前端展示层剔除非必要信息。
  • 前端展示优化:VO最适合,它针对显示优化,让页面加载更快更准确。
  • 简化代码:DTOVO都能让代码更模块化,易于理解和维护。

三、在Java中使用DTOVO的示例代码

1、定义一个基础的实体类,该类中包含用户的一些基本信息:

public class User {private Long id;private String username;private String password;private String email;private String phone;private boolean active;// 构造器,getters 和 setters 省略...
}

2、创建一个DTO,用于在不同层之间传输用户数据,同时隐藏敏感信息,比如密码:

public class UserDTO {private Long id;private String username;private String email;private String phone;private boolean active;public UserDTO(User user) {this.id = user.getId();this.username = user.getUsername();this.email = user.getEmail();this.phone = user.getPhone();this.active = user.isActive();}// getters 和 setters 省略...
}

3、定义一个VO,专门用于前端展示,进一步精简信息,只包含前端需要显示的数据:
 

public class UserVO {private String username;private String contactInfo;public UserVO(UserDTO userDTO) {this.username = userDTO.getUsername();this.contactInfo = userDTO.getEmail() + " | " + userDTO.getPhone();}// getters 和 setters 省略...
}

UserDTO从User实体类中获取数据,但不包含敏感信息,如密码。UserDTO 类,用于封装从数据库中查询出来的用户数据,并将其转换为前端需要的格式。该类只包含必要的属性(id、username、email),可以避免不必要的数据传输,提高程序的性能和效率。UserVO进一步从UserDTO中提取数据,只保留前端展示所需的用户名和联系方式。

以下是UserDTO和UserVO的转换示例,实际应用中,构造器和方法可能需要更详细的错误检查和边界处理,这里为了简洁起见,省略了这部分细节。通常会使用框架提供的工具或库(如ModelMapper、AutoMapper)来自动完成实体、DTOVO之间的转换:

// 假设我们有一个User实例
User user = new User();
// ...设置user的属性...// 将User转换为UserDTO
UserDTO userDTO = new UserDTO(user);// 将UserDTO转换为UserVO
UserVO userVO = new UserVO(userDTO);

可以看到,UserDTO 包含了用户信息的全部属性,用于在前后端之间传输数据。由于 DTO 只包含数据属性,不包含任何业务逻辑,因此可以避免数据的重复查询和传输,提高程序的性能和效率。

需要注意的是,DTOVO 只是一种设计模式,具体的实现方式可以根据具体的业务需求和技术架构来选择。在实际开发中,可以根据需要使用 DTOVO 或者其他方案来封装数据。


参考链接:https://blog.csdn.net/qq_46207024/article/details/134726394

                https://zhuanlan.zhihu.com/p/79968039


http://www.ppmy.cn/devtools/136779.html

相关文章

微信小程序中的WXSS与CSS的关系及使用技巧

微信小程序中的WXSS与CSS的关系及使用技巧 引言 在微信小程序的开发中,样式的设计与实现是构建用户友好界面的关键。微信小程序使用WXSS(WeiXin Style Sheets)作为其样式表语言,WXSS在语法上与CSS非常相似,但也有一些独特的特性。本文将深入探讨WXSS与CSS的关系,介绍WX…

YesBut——帮助多模态理解讽刺漫画的数据集

1.概述 源码地址:https://github.com/abhi1nandy2/yesbut_dataset 论文地址:https://arxiv.org/pdf/2409.13592.pdf 讽刺是一种幽默,它通过讽刺和夸张来批评人、社会和政治,是提出问题和鼓励批判性观点的有力工具。尤其是社交媒…

jenkins 2.346.1最后一个支持java8的版本搭建

1.jenkins下载 下载地址:Index of /war-stable/2.346.1 2.部署 创建目标文件夹,移动到指定位置 创建一个启动脚本,deploy.sh #!/bin/bash set -eDATE$(date %Y%m%d%H%M) # 基础路径 BASE_PATH/opt/projects/jenkins # 服务名称。同时约定部…

[论文阅读]Can GNN be Good Adapter for LLMs?

Can GNN be Good Adapter for LLMs? http://arxiv.org/abs/2402.12984 WWW 24: Proceedings of the ACM Web Conference 2024 研究背景和问题: (1)实际应用场景和问题提出 大型语言模型(LLM)在自然语言处理&…

CPU详细介绍

CPU(中央处理器,Central Processing Unit)是计算机系统的核心部件之一,被称为计算机的“大脑”。它负责执行计算机程序中的各种指令,并管理和协调计算机系统的各个硬件组件。以下是对 CPU 的详细介绍,包括其…

Python 爬虫 (1)基础 | 基础操作

一、基础操作 1、快速构建一个爬虫 ConvertCurl: https://curlconverter.com/选择URL,点击右键,选择 Copy >> Copy as cURL(bash) 安装JS环境:https://www.jb51.net/python/307069k7q.htm

mysql-分析并解决可重复读隔离级别发生的删除幻读问题

在 MySQL 的 InnoDB 存储引擎中,快照读和当前读的行为会影响事务的一致性。让我们详细分析一下隔离级别味可重复读的情况下如何解决删除带来的幻读。 场景描述 假设有一个表 orders,其中包含以下数据: 事务 A 执行快照读 START TRANSACTION…

(微信小程序)基于Spring Boot的校园失物招领平台的设计与实现(vue3+uniapp+mysql)

💗博主介绍💗:✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示:文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…