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

news2024/11/24 9:49:31

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

大家可能会有个疑问,既然DTO是展示层与服务层之间传递数据的对象,为什么还需要一个VO呢?对!对于绝大部分的应用场景来说,DTO和VO的属性值基本是一致的,而且他们通常都是POJO,因此没必要多此一举,但不要忘记这是实现层面的思维,对于设计层面来说,概念上还是应该存在VO和DTO,因为两者有着本质的区别,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的形式返回,其中可能包括所有“男性”类别的产品信息。这样,无论前端如何展示(如“帅哥”或“靓仔”),后端只需处理统一的“男性”类别,实现了前后端的解耦。

两者的关系:

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

二、使用场景

DTO

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

VO

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

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

三、在Java中使用DTO和VO的示例代码

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)来自动完成实体、DTO和VO之间的转换:

// 假设我们有一个User实例
User user = new User();
// ...设置user的属性...

// 将User转换为UserDTO
UserDTO userDTO = new UserDTO(user);

// 将UserDTO转换为UserVO
UserVO userVO = new UserVO(userDTO);

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

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


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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2246591.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ngrok实现内网穿透(Windows)

Ngrok实现内网穿透(Windows) 什么是内网穿透,内网穿透有什么用 内网穿透(NAT traversal)是一种技术手段,使得位于内网或防火墙后面的设备能够通过外网访问。例如,如果你的计算机、服务器等设备…

如何使用Jest测试你的React组件

在本文中,我们将了解如何使用Jest(Facebook 维护的一个测试框架)来测试我们的React组件。我们将首先了解如何在纯 JavaScript 函数上使用 Jest,然后再了解它提供的一些开箱即用的功能,这些功能专门用于使测试 React 应…

力扣 三数之和-15

三数之和-15 class Solution { public:vector<vector<int>> threeSum(vector<int>& nums) {int temp 0;//定义一个二维vector数组vector<vector<int>> ans;int n nums.size();//对nums数组进行排序sort(nums.begin(), nums.end());//固定…

深度学习每周学习总结J6(ResNeXt-50 算法实战与解析 - 猴痘识别)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 目录 0. 总结ResNeXt基本介绍 1. 设置GPU2. 导入数据及处理部分3. 划分数据集4. 模型构建部分5. 设置超参数&#xff1a;定义损失函数&…

Transformer架构笔记

Attention is All You Need. 3.Model Architecture 3.1 整体架构如图 3.2 Encoder与Decoder Encoder&#xff1a;由 N 6 N6 N6个相同的Block/Layer堆叠而成。每个Block有两个子层sub-layer&#xff1a;多头注意力和MLP&#xff08;FFN&#xff0c;前馈神经网络&#xff09;&…

【大数据学习 | Spark-Core】spark-shell开发

spark的代码分为两种 本地代码在driver端直接解析执行没有后续 集群代码&#xff0c;会在driver端进行解析&#xff0c;然后让多个机器进行集群形式的执行计算 spark-shell --master spark://nn1:7077 --executor-cores 2 --executor-memory 2G sc.textFile("/home/ha…

增量预训练(Pretrain)样本拼接篇

增量预训练&#xff08;Pretrain&#xff09;样本拼接篇 一、Pretrain阶段&#xff0c;为什么需要拼接拼接&#xff1f; 为了提高pretrain效率、拓展LLM最大长度&#xff0c;随机将若干条短文本进行拼接是pretrain阶段常见手段。 二、有哪些拼接方式&#xff1f; 拼接方式一…

【AI最前线】DP双像素sensor相关的AI算法全集:深度估计、图像去模糊去雨去雾恢复、图像重建、自动对焦

Dual Pixel 简介 双像素是成像系统的感光元器件中单帧同时生成的图像&#xff1a;通过双像素可以实现&#xff1a;深度估计、图像去模糊去雨去雾恢复、图像重建 成像原理来源如上&#xff0c;也有遮罩等方式的pd生成&#xff0c;如图双像素视图可以看到光圈的不同一半&#x…

从零开始-VitePress 构建个人博客上传GitHub自动构建访问

从零开始-VitePress 构建个人博客上传GitHub自动构建访问 序言 VitePress 官网&#xff1a;VitePress 中文版 1. 什么是 VitePress VitePress 是一个静态站点生成器 (SSG)&#xff0c;专为构建快速、以内容为中心的站点而设计。简而言之&#xff0c;VitePress 获取用 Markdown…

使用uniapp编写APP的文件上传

使用uniapp插件文件选择、文件上传组件&#xff08;图片&#xff0c;视频&#xff0c;文件等&#xff09; - DCloud 插件市场 实用效果&#xff1a; 缺陷是只能一个一个单独上传

【51单片机】红外遥控

学习使用的开发板&#xff1a;STC89C52RC/LE52RC 编程软件&#xff1a;Keil5 烧录软件&#xff1a;stc-isp 开发板实图&#xff1a; 文章目录 红外遥控硬件电路 NEC协议编码编程实例LCD1602显示Data红外遥控控制扇叶转速 红外遥控 红外遥控是利用红外光进行通信的设备&#…

【解决】Unity TMPro字体中文显示错误/不全问题

问题描述&#xff1a;字体变成方块 原因&#xff1a;字体资源所承载的长度有限 1.找一个中文字体放入Assets中 2.选中字体创建为TMPro 字体资源 3.选中创建好的字体资源&#xff08;蓝色的大F&#xff09; 在右边的属性中找到Atlas Width h和 Atlas Heigth,修改的大一点&…

深度学习:GPT-1的MindSpore实践

GPT-1简介 GPT-1&#xff08;Generative Pre-trained Transformer&#xff09;是2018年由Open AI提出的一个结合预训练和微调的用于解决文本理解和文本生成任务的模型。它的基础是Transformer架构&#xff0c;具有如下创新点&#xff1a; NLP领域的迁移学习&#xff1a;通过最…

CKA认证 | Day2 K8s内部监控与日志

第三章 Kubernetes监控与日志 1、查看集群资源状态 在 Kubernetes 集群中&#xff0c;查看集群资源状态和组件状态是非常重要的操作。以下是一些常用的命令和解释&#xff0c;帮助你更好地管理和监控 Kubernetes 集群。 1.1 查看master组件状态 Kubernetes 的 Master 组件包…

概念解读|K8s/容器云/裸金属/云原生...这些都有什么区别?

随着容器技术的日渐成熟&#xff0c;不少企业用户都对应用系统开展了容器化改造。而在容器基础架构层面&#xff0c;很多运维人员都更熟悉虚拟化环境&#xff0c;对“容器圈”的各种概念容易混淆&#xff1a;容器就是 Kubernetes 吗&#xff1f;容器云又是什么&#xff1f;容器…

JDBC编程---Java

目录 一、数据库编程的前置 二、Java的数据库编程----JDBC 1.概念 2.JDBC编程的优点 三.导入MySQL驱动包 四、JDBC编程的实战 1.创造数据源&#xff0c;并设置数据库所在的位置&#xff0c;三条固定写法 2.建立和数据库服务器之间的连接&#xff0c;连接好了后&#xff…

移动充储机器人“小奥”的多场景应用(上)

在当前现代化城市交通体系中&#xff0c;移动充储机器人“小奥”发挥着至关重要的作用。该机器人不仅是一个简单的设备&#xff0c;而是一个集成了高科技的移动充电站&#xff0c;为新能源汽车提供了一种前所未有的便捷充电解决方案。该机器人配备了先进的电池管理系统&#xf…

element dialog会隐藏body scroll 导致tab抖动 解决方案如下

element dialog会隐藏body scroll 导致tab抖动 解决方案如下 在dialog标签添加 :lockScroll"false"搞定

Android 功耗分析(底层篇)

最近在网上发现关于功耗分析系列的文章很少&#xff0c;介绍详细的更少&#xff0c;于是便想记录总结一下功耗分析的相关知识&#xff0c;有不对的地方希望大家多指出&#xff0c;互相学习。本系列分为底层篇和上层篇。 大概从基础知识&#xff0c;测试手法&#xff0c;以及案例…

Bugku CTF_Web——my-first-sqli

Bugku CTF_Web——my-first-sqli 进入靶场 随便输一个看看 点login没有任何回显 方法一&#xff1a; 上bp抓包 放到repeter测试 试试万能密码&#xff08;靶机过期了重新开了个靶机&#xff09; admin or 11--shellmates{SQLi_goeS_BrrRrRR}方法二&#xff1a; 拿包直接梭…