规范化JavaBean

news2024/9/20 13:20:55

Java Bean 是一个很常见的概念,简单来说就是一个 Java 类,其中的内容就是各种属性,以及各个属性的
getter/setter 。例如:

class Student {
  private String name;
  private int age;
  public String getName() {
    return this.name;
 }
  public void setName(String name) {
    this.name = name;
 }
  public int setAge() {
    return this.age;
 }
  public void setAge(int age) {
    this.age = age;
 }
}

除了 Java Bean 这样的概念之外还有很多类似和相关的概念,《码出高效——阿里巴巴Java开发手册》中就还有
DO、DTO、VO 的概念,另外,在更高级的建模领域还有 POJO、Entity、Value Object 的概念。
大概念上,上面的各种 O 都是 Java Bean 的具体情况,或者说是更细化的情况。在高级的程序员手里,实际上直接
去使用 Java Bean 的情况并不多,更多的情况是在不同地方使用不同的 O 。
在本片笔记中,我们就来看下各种 O 的概念、使用场景以及之间的异同。当然,实际上还不止上面这些 O,我们仅
介绍最常见的几种 Java Bean 。

1. DO / PO

DO,Database Object 数据库对象。由于单词  do 在 Java 中是关键字(do-while 循环),所以在有些地方会避免
使用 DO 这个称呼,转而叫它 PO,Persistence Object 持久化对象。我个人也倾向于叫它 PO 。
无论是赤裸裸地叫数据库对象,还是委婉地叫持久化对象,很显然,这个 O 的概念一定是和数据库有关系的。
简单来说,一个 DO 类是和一个数据库中的表一一对应的 。它也是我们最常见的一种 Java Bean 。无论我们的项目
的持久层框架使用的是 Mybatis 还是 JPA/Hibernate,我们的项目中一定会有 DO / PO 的身影。
理论上来说,不考虑故意不对外暴露的情况,你有多少张表,你就会有多少个 DO 类;你的表有多少个字段,你的
DO 类就会有多少个属性;你的表的字段是什么类型,你的 DO 类的属性就是对应的什么类型。

2. DTO

DTO,Data Transfer Object 数据传输对象。它是用于 Service 层的。
Service 层调用 DAO 层时,DAO 层返回的时 DO/PO 对象,这个大家都能想到,相信大家平时的代码中也是这么写
的。但是 Controller 调用 Service 层,或者 Service 调另一个 Service 时返回的则是 DTO 对象。
为什么 Service 层不直接返回 DO/PO 对象,而又要再弄出一个 DTO 对象呢?原因有二。
1. 如果 Service 层直接返回了 DO/PO 对象,那么就会对外暴露你的数据库的表结构。
有时候,你返回的只是部分数据(数据库中的数据的部分字段),这样的话,返回 DO/PO 对象即有风险又没有
必要。
这样的话,你可以重新定义一个 DTO 类,这个类中只包含你有必要返回的那些字段,这样,调用 Service 的人
就无法知道数据库中除了 DTO 中定义的字段之外还有什么字段。
2. 简化数据的关系。
对于数据库中有一对多的情况,例如,你的数据库中有学生表和班主任表,学生和班主任是一对多的关系。那
么,你的学生类肯定是这样定义的。

class StudentPO {
  private String name;
  private int age;
 ...
  private TeacherPO teacher;
}

如果你要查询一个学生的信息,并且要【顺带】查出它的班主任的信息,那么你在获得这个学生信息之后打印他的老
师的信息时,你使用学生对象的代码肯定是这样的:

System.out.println(tom.getName());
System.out.println(tom.getAge());
System.out.println(tom.getTeacher().getName());
System.out.println(tom.getTeacher().getPhone());

对于 DO/PO 对象,你需要【说】:学生的老师的名字,学生的老师的电话。通过,重定义一个 DTO 对象,你完全可以写出这样的代码:

class StudentDTO {
 private String name;
 private int age;
 private String teacherName;
 private String teacherPhone;
}

使用 DTO 的代码就可以是这样的:

System.out.println(tom.getName());
System.out.println(tom.getAge());
System.out.println(tom.getTeacherName());
System.out.println(tom.getTeacherPhone());

需要注意的是,如果你的 Service 层中多了 DTO 的定义,那么你的 Service 的职责中就多了一项:将 DAO 层返回的 DO/PO 对象转换成 DTO 对象。

3. VO

实际上 VO 对象相较而言比 DO / PO / DTO 对象要少见一些。大多数情况下,需要使用 VO 对象时,可能直接就使用了 DTO 对象了。不会再额外多定义一个类。

VO,View Object 从名字上看,它适合视图层有关的。
VO 对象面对的情况和 DTO 对象的情况类是。Controller 在调用 Service 层获得 Service 返回的 DTO 对象后,需要
将 DTO 对象转换成 VO 对象,再在 JSP 页面上展示,或者以 JSON 数据返回。
那么,问题来了:为什么需要 VO 对象,多定义一个类,而不是直接利用 DTO ,甚至是 DO / PO 对象?
不直接使用 DO / PO 对象的原因在上个章节这样已经介绍过。不直接使用 DTO 对象的原因是,DTO、DO/PO 对象中存的是【纯粹的数据】而当把数据展示在页面上时,可能需要对它进行【美化】。
什么意思呢?以 性别 为例,在数据库中人的性别大多数情况加就是用 0、1、2 这样的数值代表男、女、未知。那么,在你的 DTO、DO/PO 类中 性别 的类型就是一个简单的  int 类型。
但是在页面显示上你不可能直接显示  性别:0 、 性别:1 ,你需要将 0 和 1【美化成】男/女、先生/小姐、帅哥/美女等等个性化的内容。也即是说,至少你的 性别 要是一个字符串。
所以,Controller 要将 DTO 对象转换成 VO 对象再返回给页面或者是前端。这里就有一个转换的工作要做。

不过,上面所说的【美化】的工作其实可以转交给前端/请求方来做,没必要让 Java 后台来做这个和业务逻辑并没有太大关系的工作。因此 VO 对象其实比较少见,通常 Controller 层获得 Service 层获得到 DTO 后就返回DTO 对象,让前端/请求方自己把 0、1 【美化成】它想要显示的效果。此时,你需要在文档中和前端/调用方约定好 0、1 谁表示男,谁表示女。

4. POJO

POJO,Plain Old Java Object,很多地方都将 POJO 等同于 Java Bean,实际上 POJO 的概念要比 Java Bean 高级。
那么什么样的 Java Bean 算是一个 POJO ?
简单来说,一个 POJO 的 Java Bean 中会包含业务逻辑。这句话要是落实到代码上,那就是你的 Java Bean 除了属性的 getter / setter 方法之外还有别的(大量的)其它的方法。

例如,你定义一个钱包类:

class Wallet {
  private double money;
 ...
}

通常,我们可能只是很简单地将钱包 Wallet 类定义成这个样子,当我们的需要判断钱包中的钱是否够用时,我们是自己去【亲自写】类似这样的代码:

if (wallet.getMoney() >= xxx) {
  // 钱够用,怎么怎么着
} else {
  // 钱不够用,怎么怎么着
}

但是如果是将 Wallet 定义为 POJO 的话,那么 Wallet 的设计思路要发生变化:将【判断钱包中钱是否够用】的代码移入到 Wallet 类中,即,由 Wallet 类自己去判断钱够不够用。代码如下:

class Wallet {
  private double money;
 ...
  public boolean isEnough(double money) {
    return this.money >=  money;
 }
}

而你再使用它的时候,就只需要调用这个方法,获取结果,而不用自己去编写判断逻辑:

if (wallet.isEnough(xxx)) {
   // 钱够用,怎么怎么着
} else {
   // 钱不够用,怎么怎么着
}

概念上相当于,你不需要亲自去知道钱包中具体有多少钱,在你需要钱的时候你只需要去【问】钱包:我要 xxx 钱,你里面够不够这个数?
表面上来看,好像只是代码是在【这里】还是在【那里】的【小】问题,但是实际上这是一个类的设计思路的转变。而这个设计思路则是 DDD 建模的理论基础之一。
当然考虑到国内的普通的中小型项目极少用到 DDD 这么高级的建模方式,所以 POJO(以及基于这个概念的 Entity和 Value Object)实际上是很少见的。

你看到的叫 POJO 的类 99.99% 都是叫错了名字。POJO 类在有些地方也被叫做 Domain 类。

5. Entity 和 Value Object

简单说,Entity 和 Value Object 是 POJO 的两种具体情况。如果 POJO 类中有起 唯一性标识 作用的属性,那么这个POJO 类就是一个 Entity 类;反之则是 Value Object。
注意,此 VO(Value Object)非彼 VO(View Object),不要搞混淆了。
仍以上述的钱包 Wallet 类为例: 

如果它是 Entity,那么它应该是这样的:

class Wallet {
    private int id; // 唯一性标识
    ...
}

强调一点,并不是说有唯一性标识就一定是 Entity,首先它必须是 POJO。也即是说,这个类中要有业务逻辑方法,
不能净是些 getter/setter 这种没营养的方法。

另外,这个属性名既非必须是 int ,也非必须叫 id。无论是什么类型什么名字,这个属性是起到了唯一性标识的作用,那都行。
如果它是 Value Object,那么它里面就没有这个 id 属性。

至于什么时候用 Entity,什么时候用 Value Object 我们这里就不展开说了,毕竟非 DDD 建模的项目中用不上它们。

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

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

相关文章

网络协议与Netty

1、讲一讲什么是RPC? 说到RPC就必须要聊一聊单体项目和分布式/微服务项目 单体项目时:一次服务调用发生在同一台机器上的 同一个进程内部 ,也就是说调用发生在本机内部,因此也被叫作本地方法调用。 分布式/微服务项目时&#x…

负载均衡:定义与核心作用

负载均衡:定义与核心作用 一、负载均衡的定义二、负载均衡的核心作用 💖The Begin💖点点关注,收藏不迷路💖 负载均衡,作为网络技术的重要一环,对优化资源利用和提升服务器响应速度至关重要。本文…

Ps:首选项 - 界面

Ps菜单:编辑/首选项 Edit/Preferences 快捷键:Ctrl K Photoshop 首选项中的“界面” Interface选项卡可以定制 Photoshop 的界面外观和行为,从而创建一个最适合自己工作习惯和需求的工作环境。这些设置有助于提高工作效率,减轻眼…

快速带你玩转高性能web服务器

目录 一.Web 服务基础介绍 ​编辑1.1 互联网发展历程回顾 1.2 Web 服务介绍 1.2.1 Apache的图标 1.2.2 NGINX的图标: 1.2.3 Apache 经典的 Web 服务端 1.2.3.1 Apache prefork 模型 1.2.3.2 Apache worker 模型 1.2.3.3 Apache event模型 1.2.4 Nginx-高性能的 Web …

PanDownload 网页复刻版最新PHP源码

源码介绍 PanDownload 网页复刻版,PHP语言版,PanDownload在线解析下载的优点,速度快,受用户自身带宽限制,就是说你的宽度交多少决定你下载的速度,不用下载百度网盘客户端,你可以直接使用解析所…

PingCAP 携手 CCF 数据库专委会打造“开源数据库领域拔尖创新人才培育计划”,共塑数据库教育未来丨NDBC 2024

2024 年 8 月 7 日 - 10 日,由中国计算机学会主办、中国计算机学会数据库专业委员会和新疆大学承办、新疆 IT 三会等单位协办的第 41 届中国数据库学术会议(NDBC 2024)在新疆乌鲁木齐成功举办。 大会上 PingCAP 联合创始人黄东旭发表了主题演…

LabVIEW深度监测系统

随着果园机械化作业的迅速发展,传统的人工监测方式已难以满足现代农业的高效率与精准性需求。本文介绍了一种基于LabVIEW软件的果园开沟深度监测系统,该系统通过集成先进的传感技术与数据处理算法,实现了对开沟深度的实时精确监测和自动控制&…

11.SPI通信

SPI理论 常规四线:SCLK、CS、MOSI(主向从发)、MISO(从向主发) 同步、串行、全双工、速率(MHz) 一主一从、一主多从、不能多主 工作模式: CPOL 0:总线空闲状态时钟为低电平,1:总线空闲状态时钟为高电平 CPHA 0&#…

【Python系列】执行 Shell 命令的六种方法

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

0.91寸OLED迷你音频频谱

一、简介 音频频谱在最小0.91寸OLED 屏幕上显示,小巧玲珑 二、应用场景 本模块为音频频谱显示模块,用来获取声音频谱并展示频谱,跟随音乐声音律动 三、产品概述 基于主控芯片设计的将声音采集分析频谱,显示到0.91寸OLED的功能…

【Git】常见命令的使用

Git 介绍流程安装常见命令本地仓与远程仓关联 介绍 Git、Svn:版本控制器(用于多人团队协作) Svn:集中式版本控制器;版本库集中放在中央服务器,操作非常简单,鼠标右键提交、新增、下载 Git&…

华为OD机试 - 模拟目录管理 - 栈(Java 2024 D卷 100分)

华为OD机试 2024D卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(D卷C卷A卷B卷)》。 刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测…

博弈论,CF 1600E - Array Game

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1600E - Array Game 二、解题报告 1、思路分析 记最长递增前缀长度为L&a…

点云倒角距离(Chamfer Distance,CD)

本文为专栏《Python三维点云实战宝典》系列文章,专栏介绍地址“【python三维深度学习】python三维点云从基础到深度学习_python3d点云从基础到深度学习-CSDN博客”。配套书籍《人工智能点云处理及深度学习算法》提供更加全面和系统的解析。 点云倒角距离&#xff08…

零基础5分钟上手亚马逊云科技-高可用Web系统设计最佳实践

简介: 欢迎来到小李哥全新亚马逊云科技AWS云计算知识学习系列,适用于任何无云计算或者亚马逊云科技技术背景的开发者,通过这篇文章大家零基础5分钟就能完全学会亚马逊云科技一个经典的服务开发架构方案。 我会每天介绍一个基于亚马逊云科技…

DT浏览器使用教程之如何使用智能问答

DT浏览器使用教程之如何使用智能问答, 在DT浏览器首页点智能问答, 在智能问答页面写上相关问题,点提问, 等待一会儿就可以显示出相关答案了, 点右上角保存,可以保存到DT浏览器的笔记本 DT浏览器是一款适合…

450nm 高功率蓝光激光模组使用多长时间需要更换

450nm蓝光激光模组以其独特的波长特性和高功率输出,成为了市场上备受瞩目的产品。然而,对于用户而言,了解这类高功率激光模组的使用寿命及何时需要更换,是确保工作效率和设备安全性的重要环节。本文将带大家了解450nm 高功率蓝光激…

华为流程框架梳理及实施

获取全部108页完成PPT材料,见下图

游戏发行技术体系

游戏发行技术体系 自认为一个合格的发行技术体系应该包括以下11个部分,并且进行了大致的初步能力划分。 其中,大部分的技术平台在市面上存在三方系统,固在左侧单独的列了一个三方,用来补充后续一些替代品、个人有所遗漏的内容。…

PostgreSQL案例:planning time超长问题分析

问题分析概述 库总是OOM,分析到是执行计划生成有问题,planning time 1秒,planning shared hit 100w。一通分析,定位到是统计信息基表pg_statistic膨胀,由于会话首次SQL执行时的CatCacheMiss,导致backend访…