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

规范化JavaBean

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 建模的项目中用不上它们。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • poi-tl循环放图片+文字说明
  • dm 到 dm 的 HS 同步部署
  • 入门request请求库使用
  • 5.1、生成树协议stp
  • 【ubuntu24.04】docker pull 配置
  • leetcode_62. 不同路径 + 63. 不同路径 II
  • Python青少年简明教程:数据类型和操作符
  • 微信小程序免费《短视频去水印》
  • day02-作业题
  • 小学二年级数学精选试题
  • 学习笔记——交通安全分析30
  • 企业高性能web服务器---nginx详解(基础介绍配置,核心配置)
  • MySQL系列—MySQL编译安装常见问题(或缺少依赖)及解决方法,MySQL 编译安装时需要安装的依赖(全)
  • 系统架构:分而治之
  • mysql数据库基础使用
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • 230. Kth Smallest Element in a BST
  • Android系统模拟器绘制实现概述
  • Bytom交易说明(账户管理模式)
  • FastReport在线报表设计器工作原理
  • Laravel 实践之路: 数据库迁移与数据填充
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • Ruby 2.x 源代码分析:扩展 概述
  • Terraform入门 - 3. 变更基础设施
  • vue-router的history模式发布配置
  • vue的全局变量和全局拦截请求器
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 从setTimeout-setInterval看JS线程
  • 从输入URL到页面加载发生了什么
  • 反思总结然后整装待发
  • 关于List、List?、ListObject的区别
  • 面试遇到的一些题
  • 前端性能优化——回流与重绘
  • 删除表内多余的重复数据
  • 小程序测试方案初探
  • 一份游戏开发学习路线
  • UI设计初学者应该如何入门?
  • ​​​​​​​​​​​​​​Γ函数
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • #if 1...#endif
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (2)(2.10) LTM telemetry
  • (二刷)代码随想录第15天|层序遍历 226.翻转二叉树 101.对称二叉树2
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (回溯) LeetCode 78. 子集
  • (精确度,召回率,真阳性,假阳性)ACC、敏感性、特异性等 ROC指标
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (算法)区间调度问题
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • ./和../以及/和~之间的区别
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .JPG图片,各种压缩率下的文件尺寸
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting