Java中各种O(PO,BO,DTO,VO等) 是不是人为增加系统复杂度?

Java中各种O(PO,BO,DTO,VO等) 是不是人为增加系统复杂度?

在Java和其他编程语言的开发过程中,经常会用到几个以"O"结尾的缩写,比如PO,BO,DTO,VO等等,O在这里是Object的缩写,不同的O代表了不同的数据类型,很多时候这些O中的属性看起来都是差不多的,干的事情好像也只是一个简单的封装,那么搞出这么多O出来是不是人为增加了系统的复杂度呢?

各种O都是干什么的?

想要搞清楚标题中的问题,我们首先得了解这些O都是什么东西?这里给大家介绍几种常见的O:

  1. PO (Persistent Object) - 持久化对象。持久化对象通常对应数据库中的一个表,主要用于表示数据库中存储的数据。PO中的属性通常和数据表的列一一对应,用于ORM(对象关系映射)框架中,如Hibernate,JPA等。
  2. BO (Business Object) - 业务对象。业务对象主要封装了业务逻辑。它可以包含多个PO,或者是一个PO的扩展,增加了业务处理的逻辑。BO通常在业务层被使用,用于实现业务操作,比如计算、决策等。
  3. VO (Value Object) - 值对象。值对象是一种用于传输数据的简单对象,它通常不包含业务逻辑,只包含数据属性和get/set方法。值对象主要用于业务层与表示层之间的数据传递,它的数据可能是由多个PO组合而成。
  4. DTO (Data Transfer Object) - 数据传输对象。数据传输对象类似于VO,它也是用于层与层之间的数据传递。DTO通常用于远程通信,比如Web服务之间的数据传递。DTO通常不包含任何业务逻辑,只是用于在不同层次或不同系统之间传输数据。

有时候我们还会看到DO、POJO等概念,它们又是什么呢?

  1. DO (Domain Object) - 领域对象。领域对象是指在问题领域内被定义的对象,它可以包含数据和行为,并且通常代表现实世界中的实体。在DDD(领域驱动设计)中,领域对象是核心概念,用于封装业务逻辑和规则。这里需要注意DO和BO的区别,虽然都是搞业务逻辑,DO通常是业务领域中单一实体的抽象,它关注于单个业务实体的属性和行为;而BO则通常涉及到业务流程的实现,可能会协调多个DO来完成一个业务操作。
  2. POJO (Plain Old Java Object) - 简单老式Java对象。POJO是指没有遵循特定Java对象模型、约定或框架(如EJB)的简单Java对象。POJO通常用于表示数据结构,它们的实例化和使用不依赖于特定的容器或框架。

为什么要划分各种O?

在软件开发中划分不同的O主要是为了实现关注点分离(Separation of Concerns,SoC),提高代码的可维护性、可读性和可扩展性。

下面展开列举了一些划分这些对象的原因:

  1. 明确职责:通过将不同的职责分配给不同的对象,可以使每个对象都有明确的职责,这样代码更容易理解和维护。
  2. 减少耦合:不同层次之间通过定义清晰的接口(如特定的对象)交互,减少了直接的依赖关系,降低了耦合度。
  3. 抽象层次:通过定义不同的对象,可以在不同的抽象层次上操作,比如在数据层处理PO,在业务层处理BO,这样可以在合适的层次上做出决策。
    • 灵活性:当系统需要变更时,由于职责和层次的清晰划分,更容易做出局部的修改而不影响到整个系统。不同的对象可能针对性能有不同的优化,例如PO可能被优化以提高数据库操作的性能。
    • 安全性:通过使用不同的对象,可以控制敏感数据的暴露。例如,可以在DTO中排除一些不应该传输到前端的敏感信息。
    • 测试性:分离的对象使得单元测试变得更加容易,因为可以针对每个对象进行独立的测试。
  1. 交互清晰:在不同的系统组件或层次之间传递数据时,清晰的对象定义可以让数据交互更加清晰,减少数据传递中的错误。

总之,通过划分各种“O”对象,开发者可以更好地组织代码,将复杂系统分解为更小、更易于管理的部分,同时也有助于团队成员之间的沟通和协作。这种划分在设计模式和软件工程实践中是一种常见且有效的方法。

OO不分的惨痛经历

说个实际的惨痛经验。

很多时候我会感觉这些O之间存在很多重复的代码,比如重复的属性定义、简单的方法封装,DRY(Don't Repeat Yourself)原则不是说让大家避免重复嘛,所以我也曾经尝试在程序中统一它们。

但是总有一些O之间存在或多或少的差异,比如:

  • 这个O需要一个A属性,仅用于内部状态管理,不会暴露到外部,其它O都不需要。
  • 还有这个接口需要返回一个B属性,其它接口都不需要。

这时候,你怎么办?如果使用同一个类型,那就得加上这些属性,尽管它们在某些时候用不到。根据你的选择,你可能在所有的地方都给这个属性赋值,也可能仅在业务需要的时候给他们赋值。

看个实际的例子:在一个复杂的电商系统中,商品的管理可能涉及到库存管理、价格策略、促销信息等多个方面。

// 商品类
public class Product {private Long id; // 来自商品表private String name; // 来自商品表private double price; // 来自商品表,传输时需要特殊格式private int stock; // 来自库存表,仅在下单判断中需要,展示层不需要private String promotionInfo; // 来自促销表,展示层需要// 构造器、getter和setter方法省略
}

但是这却带来了很大的危害:

  • 调用接口的同学会问,这个属性什么时候会有值,什么时候会没值?
  • 优化的同学会问,计算这个属性的值会影响性能,能删掉吗?
  • 交接的同学会问,这个属性是干什么用的,为什么不给他赋值?

总之会增加了大量的沟通成本与维护难度。一旦这样做了,后边就会特别别扭,改不完,根本改不完。

在软件工程化的今天,各类O的设计看似增加了复杂度,但是实际上是对系统模块化、职责划分以及实际应用场景的合理抽象和封装,有助于提高软件质量和团队协作效率。

老老实实写吧,不同的O就是不同的东西,它们不是重复的,只是在代码上看着像,就像人有四肢,动物也有四肢,但是它们不能共用,否则出来的就是四不像。

图片来源:https://ozhanozturk.com/2018/01/28/chimera-kimera-mitoloji/

当然如果只是一个很简单的程序或者一次性的程序,我们确实没必要划分这么多的O出来,直接在接口方法中访问数据库也不是不可以的。

前端中O的使用

虽然各种O一般活跃在各种后端程序中,但是前端也不乏O的身影,只是没有后端那么形式化。

以下是一些可能在前端开发中遇到的以“O”结尾的数据对象:

  1. VO (View Object) - 视图对象。在前端框架中,VO可以代表专门为视图层定制的数据对象。这些对象通常是从后端接口获取的数据经过加工或格式化后,用于在界面上显示的对象。
  2. DTO (Data Transfer Object) - 数据传输对象。虽然DTO通常用于后端服务间的数据传输,但在前端中也可以用来表示从后端接口获取的数据结构。前端的DTO通常是指通过Ajax或Fetch API从服务器获取的原始数据结构。
  3. VMO (ViewModel Object) - 视图模型对象。在MVVM(Model-View-ViewModel)架构中,VMO可以代表视图模型对象,它是模型和视图之间的连接器。在Vue.js中,Vue实例本身就可以被看作是一个VMO,因为它包含了数据和行为,同时也是视图的反映。
  4. SO (State Object) - 状态对象 尽管不是标准的术语,但在使用如Vuex这样的状态管理库时,SO可以用来指代代表应用状态的对象。这些状态对象通常包含了应用的核心数据,如用户信息、应用设置等。

在实际的Vue开发过程中,开发者可能不会严格区分这些概念,而是更多地关注于组件的状态、属性(props)、事件和生命周期。组件内部的数据通常以数据属性(data)的形式存在,而组件间的数据传递通常使用属性(props)和事件(emits)。在处理与后端的数据交互时,开发者可能会定义一些专门的对象来适应后端的接口,但是这些都不是Vue框架强制的概念或规则。


简单地说,这些“O”其实就是帮我们把代码写得更清晰、更有条理,虽然一开始看着很麻烦,但时间一长,你会发现这样做能省下不少力气。就像我们的衣柜,虽然分类放好衣服需要点时间,但每天早上起来挑衣服的时候,不就轻松多了吗?

所以,别被这些专业术语吓到,它们其实就是帮我们把事情做得更好的小工具。每个“O”都有它的用处和场景,我们要做的,就是搞清楚什么时候戴哪顶帽子,这样生活和编程都能变得轻松愉快。记住,合适的工具用在合适的地方,能让你事半功倍!

关注萤火架构,加速技术提升!

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

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

相关文章

Java基础 - 13 Queue之DelayQueue、PriorityQueue、PriorityBlockingQueue讲解

在Java的队列世界里,有三位大佬,他们分别是DelayQueue、PriorityQueue和PriorityBlockingQueue。今天,让我们一起揭开他们神秘的面纱,看看他们各自的特点和用途吧! DelayQueue 首先,让我们来认识一下Delay…

2.22 作业

顺序表 运行结果 fun.c #include "fun.h" seq_p create_seq_list() {seq_p L (seq_p)malloc(sizeof(seq_list));if(LNULL){printf("空间申请失败\n");return NULL;}L->len 0; bzero(L,sizeof(L->data)); return L; } int seq_empty(seq_p L) {i…

工厂方法模式Factory Method

1.模式定义 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使得一个类的实例化延迟到子类 2.使用场景 1.当你不知道改使用对象的确切类型的时候 2.当你希望为库或框架提供扩展其内部组件的方法时 主要优点: 1.将具体产品和创建…

PHP+vue+mysql仓库进销存管理系统8jeqj

开发语言:php 后端框架:Thinkphp 前端框架:vue.js 服务器:apache 数据库:mysql 运行环境:phpstudy/wamp/xammp等 数据库工具:Navicat/phpmyadmin 登录模块:此模块主要有4个部分,基…

实验中用户行为的检测

[1] Makris S , Karagiannis P , Koukas S ,et al.Augmented reality system for operator support in human–robot collaborative assembly[J].CIRP Annals - Manufacturing Technology, 2016:S0007850616300385.DOI:10.1016/j.cirp.2016.04.038. —————————————…

什么是SSD型云服务器?

​  SSD云服务器是一种使用固态硬盘代替传统HDD进行存储的虚拟机。SDD 使用闪存单元来存储数据,与云计算技术相结合,形成强大且高效的存储解决方案,可以随时随地访问。 SSD云服务器如何工作? SSD云服务器是利用虚拟化和云计算技术创建的。…

C++最佳实践之编译篇

C最佳实践之工程编译 在大型c/c工程开发中,往往会涉及多级CMakeLists.txt的调用,并且调用方式错综复杂,主要有以下两种方式: 1. 子目录中的CMakeList.txt独立生成目标,不作为主目标生成过程的依赖关系(比…

virtualenv env_name 使用 virtualenv 创建 python 虚拟环境

为什么要用这个 win7 32 环境下 pycharm 只能用低版本的,比如 2016,2018 此时pycharm 图形界面创建的 虚拟环境版本很低,有些包不兼容,因此用 virtualenv 模块,可以创建 20 版本以上的虚拟环境 virtualenv env_name官方文档 http…

如何选择最适合的图纸加密软件?安秉网盾软件用户体验及性价比

安秉网盾图纸加密软件是一款功能强大的图纸加密工具,具有以下特点和优势: 全盘加密:安秉网盾采用先进的加密算法,能对文件、文件夹、磁盘等数据进行全面加密,确保数据在存储和传输过程中的安全性。 监控与审计&#x…

关于el-select值的回显问题 : 框内显示label值还是value值

<el-form-item label"状态" prop""><el-selectv-model"roleForm.state"class"m-2"size"large"style"width: 240px"placeholder"请选择状态"value-key"value"//value-key 与下面的ke…

How to implement multiple file uploads based on Swagger 3.x in Spring boot 3.x

How to implement multiple file uploads based on Swagger 3.x in Spring boot 3.x Projectpom.xmlOpenAPIConfigFileUploadControllerapplication.yaml Project pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://…

软件压力测试:测试方法与步骤详解

随着软件应用的不断发展&#xff0c;用户对系统性能的要求也逐渐提高。在不同的负载条件下&#xff0c;系统必须能够保持稳定、高效的运行。软件压力测试是一种验证系统在各种负载情况下性能表现的关键手段。本文将详细探讨软件压力测试的方法和步骤。 1. 明确测试目标 在进行压…

vue源码分析之nextTick源码分析-逐行逐析-错误分析

nextTick的使用背景 在vue项目中&#xff0c;经常会使用到nextTick这个api&#xff0c;一直在猜想其是怎么实现的&#xff0c;今天有幸研读了下&#xff0c;虽然源码又些许问题&#xff0c;但仍值得借鉴 核心源码解析 判断当前环境使用最合适的API并保存函数 promise 判断…

2024年2月17日~2月23日周报

文章目录 一、前言二、DDNet架构学习2.1 数据预处理2.2 网络模型构建 三、基于深度学习地震数据去噪处理3.1 深度学习在地震数据去噪中的研究方向3.2 深度学习地震数据去噪流程3.2.1 数据集准备3.2.2 模型构建3.2.3 训练网络 3.3 基于DnCNN的地震数据去噪实验 四、小结4.1 存在…

Javascript数字精度丢失的问题

一、问题 0.1 0.2 0.3 // false 二、浮点数 “浮点数”是一种表示数字的标准&#xff0c;整数也可以用浮点数的格式来存储 我们也可以理解成&#xff0c;浮点数就是小数 在JavaScript中&#xff0c;现在主流的数值类型是Number&#xff0c;而Number采用的是IEEE754规范中…

uniapp开发微信小程序跳转到另一个小程序中

注意&#xff1a;一开始我的云上务工模块是单独的tabbar界面&#xff0c;但是小程序跳转好像不能直接点击tabbar进行&#xff0c;所以我将这里改成了点击首页中的按钮进行跳转 点击这里进行小程序跳转 目录 基础讲解 uniapp小程序跳转的两个方法 调用说明&#xff08;半屏跳转…

C++力扣题目 647--回文子串 516--最长回文子序列

647. 回文子串 力扣题目链接(opens new window) 给定一个字符串&#xff0c;你的任务是计算这个字符串中有多少个回文子串。 具有不同开始位置或结束位置的子串&#xff0c;即使是由相同的字符组成&#xff0c;也会被视作不同的子串。 示例 1&#xff1a; 输入&#xff1a…

面试系列之《Spark》(持续更新...)

参考文档及示例代码均基于pyspark3.1.2 1.什么是RDD&#xff1f;2.job、stage、task如何划分&#xff1f;3.什么是宽窄依赖&#xff1f;4.spark有哪几种部署模式&#xff1f;5.spark中的算子分为哪些类型&#xff0c;举例说明。6.cache、persist、checkpoint的区别&#xff0c;…

C++模板为什么不能声明和定义分离

首先我们要直到C程序运行需要进行的四个阶段。 预处理->编译->汇编->链接 编译&#xff1a;对语法语义分析&#xff0c;分析无误生成汇编&#xff0c;头文件不参加编译&#xff0c;多个源文件是分开单独编译的。 链接&#xff1a;将多个obj文件链接合成一个&#x…

Sora----打破虚实之间的最后一根枷锁----这扇门的背后是人类文明的晟阳还是最后的余晖

目录 一.Sora出道即巅峰 二.为何说Sora是该领域的巨头 三.Sora无敌的背后究竟有怎样先进的处理技术 1.Spacetime Latent Patches 潜变量时空碎片&#xff0c;建构视觉语言系统 2.扩散模型与Diffusion Transformer&#xff0c;组合成强大的信息提取器 3.DiT应用于潜变量时…