当前位置: 首页 > news >正文

【简略知识】项目开发中,VO,BO,PO,DO,DTO究竟是何方妖怪?

前言

在项目开发中,是否需要定义VO(视图对象),BO(业务对象),PO(持久化对象),DO(领域对象),DTO(数据传输对象)取决于项目的规模、复杂性、团队的协作方式以及项目的长远规划。

对于小型或者简单的项目,如果团队成员较少,项目需求稳定且迭代速度不是很快,确实可以不严格区分这些对象,使用简单的POJO(Plain Old Java Object)来进行各层之间的数据传递。这样做可以减少项目的复杂度,加快开发进度。

然而,对于大型或复杂的项目,尤其是那些需要长期迭代和维护的,以及参与人员较多的项目,定义这些不同的对象有其必要性:

  1. VO(视图对象):它们用于前端展示,可以屏蔽后端数据结构的变化对前端的影响,有助于保持前后端的分离和松耦合。
  2. DTO(数据传输对象):在服务层和展示层之间传输数据时使用,它们可以减少网络传输的数据量,提高性能,并且可以在不同层次之间提供一个清晰的界限。
  3. BO(业务对象):封装了业务逻辑,可以提高代码的复用性,使得业务逻辑更加清晰,易于维护。
  4. PO(持久化对象):它们与数据库结构直接对应,有助于实现数据访问层的封装,降低持久化逻辑与业务逻辑的耦合。
  5. DO(领域对象):它们代表业务领域的概念,有助于构建领域模型,促进开发人员与业务专家之间的沟通。

易混点一:VO和DTO

首先VO是最常用的,但对于这个概念,网上也是众说纷纭,value object 或 view object,一般说视图对象或者值对象,我更倾向理解为视图对象。说白了它就是展示用的,不管展示方式是网页,还是客户端,还是APP,只要是这个东西是让人看到的,我们就把它封装为VO。

VO比较容易混淆的是DTO,DTO是展示层与服务层之间传递数据的对象,可以这样说,对于绝大部分的应用场景来说,DTO和VO的属性值基本是一致的,而且他们通常都是POJO,那么既然有了VO,为什么还需要DTO呢?

我们举例来说明一下:

某公司有一个后台服务,服务层有一个getUser的方法返回一个系统用户,包含sex(性别)、年龄。对于服务层来说,DTO只从语义上定义,可能是这样的:

{"gender":"男","age":35
}

但这个服务同时供多个客户端使用(不同门户),而不同的客户端对于表现层的要求有所不同,比如管理端要求显示准确的年龄,而应用端为了保护客户隐私,只需要显示一个年龄段即可。

管理端VO:

{"gender":"男","age":35
}

应用端VO:

{"gender":"男","age":30~40
}

从这个例子可以看出,DTO很有存在的必要,根据职责单一原则,服务层只负责业务,与具体的表现形式无关,DTO不应该出现与表现形式的耦合,DTO定义的是原始数据,VO再对DTO数据进行解释。这下VO和DTO用法就清晰很多了。

职责单一原则(Single Responsibility Principle, SRP)是面向对象设计中的一个重要原则,由Robert C. Martin提出。该原则指出,任何一个软件单元(如类、模块或服务)都应当有且只有一个引起其变化的原因。这个原则的核心理念是提高代码的内聚性,降低耦合性,使代码更易于理解和维护。

易混点二:BO和PO

PO是持久对象,这个很好理解,就是实体和数据库字段的对应,一个PO的数据结构对应着库中表的结构,表中的一条记录就是一个PO属性,大多数情况下,PO仅仅作为PO只是用来增删改使用。

PO比较容易混淆的是BO,BO是业务对象,对应的是某个具体的业务块,可以包含多个属性、对象。简单点来说,我们可以把BO看作是PO的组合。

我们举例来说明一下:

PO-1是交易记录对象,PO-2是登录记录对象,PO-3是商品浏览记录对象,PO-4是添加购物车记录对象,PO-5是搜索记录对象,BO是个人网站行为对象,BO对象:{PO-1;PO-2;PO-3;PO-4;PO-5}。这样做的优点不言而喻,维护代码的时候查看BO,就能知道这块逻辑涉及多少表(PO)。

易混点三:BO和DTO

搞清楚了BO和PO各自的用途后,我们会发现BO和DTO有重叠功能,一样可以对PO进行排列组合,那BO的存在的意义是什么呢?

从用途上进行根本的区别,BO是业务对象,DTO是数据传输对象,虽然BO也可以排列组合数据,但它的功能是对内的,比如上个例子中的BO对象包括{PO-1;PO-2;PO-3;PO-4;PO-5}还有其他字段属性,但在提供对外接口时,BO对象中的某些属性对象可能用不到或者不方便对外暴露,那么此时DTO只需要在BO的基础上,抽取自己需要的数据,然后对外提供。

在这个关系上,通常不会有数据内容的变化,内容变化要么在BO内部业务计算的时候完成,要么在解释VO的时候完成。

DO

DO是领域对象,就是从现实世界中抽象出来的有形或无形的业务实体。事实上,DO和PO在绝大部分情况下是一一对应的。阿里巴巴的开发手册中的定义DO等同于PO,即与数据库表结构一一对应,通过DAO层向上传输数据源对象。

上一张图,更加直观的展示这些名词使用的节点:

在这里插入图片描述

总结

VO,BO,PO,DTO这样分层还是很有意义的。尤其在团队成员较多的情况下,结构更加一目了然,同时也能很大程度避免多端系统数据所需不一致时,有人修改属性影响其他页面。但也完全没有必要教条主义,把这些全部用上,需要根据所开发的业务复杂度来取舍,如果本身业务逻辑不负责,照搬全上反而让开发变的更复杂。

例如业务不复杂,根本没有多端展示的差异化,VO可以直接拿掉,直接使用DTO传输到前端数据即可。

同时在使用过程中,最重要的是要在团队中达成共识,概念一致,如果使用了这些,但各按各的理解来,甚至抓起来就直接用,反而会让代码变得更乱,还不如直接POJO、DTO打天下。

另附这些概念命名规范:

  • 数据对象:xxxPO,xxx即为数据表名。(也可DO)
  • 数据传输对象:xxxDTO,xxx为业务领域相关的名称。
  • 展示对象:xxxVO,xxx一般为网页名称。
  • 业务对象:xxxBO,xxx是业务名称。

本文参考自Java知音。1


  1. https://mp.weixin.qq.com/s/3-wA3hh75pgoTJu0Rz3SXw ↩︎

相关文章:

  • 腾讯云幻兽帕鲁服务器如何安全下载WorldOption.sav文件?
  • 抖音视频批量下载软件|视频评论采集工具
  • 开源视频转码器HandBrake
  • Godot自定义控件样式语法解析
  • Java数据类型(八种基本数据类型 + 四种引用类型)、数据类型转换
  • 机器学习:模型评估和模型保存
  • 【软考】设计模式之访问者模式
  • Redis的主从搭建
  • Linux笔记--GCC
  • 全新2.0版本极其抽象的门(Spring Security)
  • Unity RectTransform·屏幕坐标转换
  • 【研发日记】Matlab/Simulink技能解锁(三)——在Stateflow编辑窗口Debug
  • 2024目前三种有效加速国内Github
  • 算法修炼-动态规划之路径问题(1)
  • 代码随想录算法训练营第四十六天 139.单词拆分、多重背包(了解)、 背包总结
  • 分享的文章《人生如棋》
  • Docker 笔记(2):Dockerfile
  • input的行数自动增减
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • JavaScript设计模式与开发实践系列之策略模式
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • Redis中的lru算法实现
  • Unix命令
  • 关于List、List?、ListObject的区别
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • 事件委托的小应用
  • 算法---两个栈实现一个队列
  • 学习ES6 变量的解构赋值
  • [Shell 脚本] 备份网站文件至OSS服务(纯shell脚本无sdk) ...
  • 新年再起“裁员潮”,“钢铁侠”马斯克要一举裁掉SpaceX 600余名员工 ...
  • # 数据结构
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (保姆级教程)Mysql中索引、触发器、存储过程、存储函数的概念、作用,以及如何使用索引、存储过程,代码操作演示
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (四)【Jmeter】 JMeter的界面布局与组件概述
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (转)linux 命令大全
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • .Net mvc总结
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .NET/MSBuild 中的发布路径在哪里呢?如何在扩展编译的时候修改发布路径中的文件呢?
  • .NET国产化改造探索(一)、VMware安装银河麒麟
  • /etc/X11/xorg.conf 文件被误改后进不了图形化界面
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • [@Controller]4 详解@ModelAttribute
  • [2669]2-2 Time类的定义
  • [Android 数据通信] android cmwap接入点
  • [BUG]Datax写入数据到psql报不能序列化特殊字符
  • [CareerCup] 17.8 Contiguous Sequence with Largest Sum 连续子序列之和最大
  • [CC-FNCS]Chef and Churu
  • [CTF]2022美团CTF WEB WP
  • [DAU-FI Net开源 | Dual Attention UNet+特征融合+Sobel和Canny等算子解决语义分割痛点]