摘要:浅析POJO、DTO、DO、VO、BO、PO和Entity等的概念、区别及其用法。

名词解释

  领域模型中的实体类分为四种模型:VO、DTO、DO和PO,各种实体类用于不同业务层次间的交互,并会在层次内实现实体类之间的转化。新项目使用了新的框架和开发规范,特意集体讨论了DTO,DO,VO,BO,POJO,PO和Entity以及DAO、Model和View的基本概念和使用场景,为了深入理解,这里整理为一篇笔记。下面通过一张图看一下它们的大致分类:

  用MVC模式的角度接着看图,看完图估计大部分人对这些专业术语就有一个直观的感受了:

  简明扼要地综述如下:VO 用于后端向前端传输数据,DTO用于前端向后端传输数据,BO用于微服务之间传输数据。PO等同于Entity,DO是Entity的一种,三者用于表示数据库的一条记录,通常用Entity。

POJO

  总的来说,普通Java对象POJO(Pure Old Java Object 、 Plain Ordinary Java Object),按照Martin Fowler的解释是“Plain Old Java Object”,从字面上翻译为“纯洁老式的java对象”,但大家都使用“简单java对象”来称呼它。包含DO、DTO、BO、VO和PO等,它们本质上都是一个简单的java对象,实际就是普通的Java Beans。没有业务逻辑,有时可以作为VO或DTO来使用。当然,这里特意说明纯普通Java对象,如果你有一个简单的运算属性也是可以的,但不允许有业务方法。

  POJO是指这样的java对象:

  • 有一些private的参数作为对象的属性
  • 针对每一个参数定义get和set方法
  • 没有从任何类继承
  • 没有实现任何接口
  • 没有被其它框架侵入。

  许多开发者把Java Bean看作遵从特定命名约定的POJO。例如:

public class User {
private Long id;
private String userName;
private String msg;
private Integer age;
public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getUserName() {
return userName;
} public void setUserName(String userName) {
this.userName = userName;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}

  POJO其实是比java bean更纯净的简单类或接口。POJO严格地遵守简单对象的概念,而不具有业务逻辑处理的能力,而一些Java Bean中往往会封装一些简单逻辑。例如,改造User后,可以得到一个Java Bean:

public class User implements Serializable {
//实现serializable接口
private static final long serialVersionUID = -2241142936329900646L;
private Long id;
private String userName;
private String msg;
private Integer age;
/**
* 无参构造器
*/
public User() {
}
public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getUserName() {
return userName;
} public void setUserName(String userName) {
this.userName = userName;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
} public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public User(Long id, String userName, Integer age) {
this.id = id;
this.userName = userName;
this.age = age;
} }

可以把 POJO 视作 DO/DTO/BO/VO 的统称,但是,禁止把类名命名成 xxxPOJO。

VO

  VO(View Object)视图模型,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。如果是一个DTO对应一个VO,则DTO等价于VO;但是如果一个DTO对应多个VO,则展示层需要把VO转换为服务层对应方法所要求的DTO,传送给服务层,从而达到服务层与展示层解耦的效果。

  一般用在业务逻辑层(Service)对前端(Web) 的视图模型效果控制的展示上,说白了就是后台向前端传输数据。示例:xxxVO,xxx一般为网页名称。注:在展示业务不复杂的系统,可直接使用DTO。

DTO

  数据传输对象DTO(Data Transfer Object)是一个比较特殊的对象,代表控制层需要接收的数据和返回的数据。它有两种存在形式:在后端,它的存在形式是java对象,也就是在controller里面定义的请求参数,通常在后端不需要关心怎么从json转成java对象,这都是由一些成熟的框架完成的,比如spring框架;在前端,它的存在形式通常是js里面的对象(也可以简单理解成json),即通过ajax发送的请求参数。这也是为什么把DTO画成横跨两层的原因。举个例子,xxxDTO,xxx为业务领域相关的名称。

  现在微服务盛行,服务和服务之间调用的传输对象能叫DTO吗?我的理解是看情况,DTO的一个隐含意义是要能够完整的表达一个业务模块的输出。如果服务和服务之间相对独立,那就可以叫DTO;如果服务和服务之间不独立,每个都不是一个完整的业务模块,拆开可能仅仅是因为计算复杂度或者性能的问题,那这就不能够叫做DTO,只能是BO。

  DTO与BO或者DO的区别是DTO没有任何行为(方法),只是存储和提供它所拥有数据的查询(访问器和修改器)。DTO是简单对象,不包含任何需要测试的业务逻辑。

Entity/PO

  持久化对象PO(Persistent Object)等同于Entity,它们的概念是一致的。数据库表中的记录在java对象中的显示状态。最形象的理解就是一个PO对象对应数据库中的一条记录,一个PO的数据结构对应着库中一张表的表结构,即自身属性与数据表字段一一对应。好处是可以把一条记录作为一个对象处理,方便的转为其它对象。

  例如我们有一条数据,现在有一个简单类而且已经是被赋予了这条数据的实例,那么这条数据在这个简单类中的存在状态就是PO,不管这个简单类是DO还是BO抑或其它。PO只是数据持久化的一个状态。

  通常PO里面除了get,set之外没有别的方法。对于PO来说,数量是相对固定的,一定不会超过数据库表的数量。

DO

  领域对象 DO(Domain Object) 是从现实世界中抽象出来的有形或无形的业务实体,它用来接收数据库对应的实体,是一种抽象化的数据状态,介于数据库与业务逻辑之间。

  一般在业务逻辑层(Service)对数据库(SQL) 进行访问时,用于接收数据。xxxDO,xxx即为数据表名。另外,DO与Entity的不同点就是DO是与数据库存在着某种映射关系的Entity,总的来说DO是Entity的一种。

  现在主要有两个版本一个是阿里巴巴的开发手册中定义的DO( Data Object),这个等同于上面的PO;另一个是在DDD(Domain-Driven Design)领域驱动设计中定义的DO(Domain Object),这个等同于上面的BO。

BO

  业务对象(Business Object,BO)是对数据进行检索和处理的组件,主要作用是把业务逻辑封装为一个对象,这个对象可以包括一个或多个其它的对象。形象描述为一个对象的形为和动作,当然也有涉及到其它对象的一些形为和动作。

  BO通常位于中间层或者业务逻辑层。BO支持序列化和反序列化,可以轻易地将BO的Java实例转换为一个XML文件或者一个流保存起来,并且在需要的时候,将这个BO从XML或者流中转换回一个Java实例。举个简单的例子,一个简历包含教育经历、工作经历、社会关系等三个模块,每个模块对应一个PO;建立一个BO对象处理简历,则每个BO包含这三个PO。

  应用中的所有实体(Entity)都是BO,但并不是所有BO都是实体。BO包括包含方法的实体对象(Entity Object)和不包含方法的值对象(VO)。

Model

  Model是数学逻辑名词,包括有限操作的集合以及定义于其上的关系,主要用于分析、设计过程。

  实体类和模型Model在计算机程序设计中有两个概念:一个是三层架构中的实体类,另一个是MVC架构中的模型。在“三层架构”中,为了面向对象编程,将各层传递的数据封装成实体类,便于数据传递和提高可读性。在MVC(模型Model-视图View-控制器Controller)模式中,Model代表模型,是业务流程/状态的处理以及业务规则的制定,接受视图请求的数据,并返回最终的处理结果。业务模型的设计可以说是MVC最主要的核心。

View

  在MVC模式中,View代表视图,用来解析Model带来的数据模型,以展示视图数据,View的模型觉决定了需要什么样的Model来对接,相互联系。

DAO

  数据访问对象DAO (Data Access Object)是一个数据访问接口,所谓数据访问,顾名思义,就是与数据库打交道,夹在业务逻辑与数据库资源中间。一般在业务逻辑层对数据库进行访问时使用。

  xxxDAO,xxx即为实体类名(Entity实体)。在核心J2EE模式中是这样介绍DAO模式的:为了建立一个健壮的J2EE应用,应该将所有对数据源的访问操作抽象封装在一个公共API中。用程序设计的语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候就使用这个接口,并且编写一个单独的类或者xml文件,来实现这个接口在逻辑上对特定数据的操作。

放在哪个目录

  • PO通常放在名为bean、entity、model目录中。
  • DAO通常在DAO、mapper目录中。
  • BO通常在service、manager、business目录中。

POJO的扩展

  POJO仅包含最简单的字段属性,没有多余的东西,它本质上就是一个普通的JavaBean。但是在POJO的基础上,能够扩展出不同的对象。

  • 为POJO增加了持久化的方法(Insert、Update、Delete……)之后,POJO就变成了PO。

  • 为POJO增加了数据绑定功能之后,POJO就变成了View Object,即UI Model。

  • 为POJO增加业务逻辑的方法(比如单据审核、转帐……)之后,POJO就变成了Domain Model。

  • POJO还可以当作DTO使用。

示例说明

  假如一张表有100个字段且视图层需要展示其中10个属性,那么对应的PO就有100个属性,PO对应的DTO就有10个属性,没有必要把整个PO对象传递到客户端,而是从控制层把拥有这10个属性的DTO对象传递到视图层,这样也不会暴露服务端表结构;在数据到达客户端以后,如果用这个对象来对应界面显示,那此时它的身份就转为VO。

如何使用

  项目中真的有必要定义领域驱动模型VO、DTO、BO、PO吗?依据业内开发经验,敏捷开发项目通常用DTO,复杂项目遵守规范。

  一些工具类的系统和一些业务不是很复杂的系统DTO是可以和BO合并成一个,VO是可以第一个优化掉的,展示业务不复杂的可以压根儿不要,直接用DTO。

概念是给人用的,持续迭代的团队协作项目,这个时候我们就建议用VO,BO,PO,DO,DTO,而且团队内要达成共识,形成一个标准规范,这也是最重要的一条。业务规模庞大,团队协同频繁的场景下,遵守规范会让服务更具扩展性和可读性,让类语义更明确,从而使不同程序猿很容易理解类的含义和业务逻辑,进而提升项目的健壮性、可扩展性、可维护性与可阅读性。提升这些性能的尽头是经济效益,降低开发运维成本。

Reference

浅析领域驱动模型VO、DTO、BO、PO 等的概念、区别及其用法的更多相关文章

  1. 领域驱动模型DDD(二)——领域事件的订阅/发布实践

    前言 凭良心来说,<微服务架构设计模式>此书什么都好,就是选用的业务过于庞大而导致代码连贯性太差,我作为读者来说对于其中采用的自研框架看起来味同嚼蜡,需要花费的学习成本实在是过于庞大,不仅 ...

  2. 【tornado】系列项目(二)基于领域驱动模型的区域后台管理+前端easyui实现

    本项目是一个系列项目,最终的目的是开发出一个类似京东商城的网站.本文主要介绍后台管理中的区域管理,以及前端基于easyui插件的使用.本次增删改查因数据量少,因此采用模态对话框方式进行,关于数据量大采 ...

  3. 【tornado】系列项目(一)之基于领域驱动模型架构设计的京东用户管理后台

    本博文将一步步揭秘京东等大型网站的领域驱动模型,致力于让读者完全掌握这种网络架构中的“高富帅”. 一.预备知识: 1.接口: python中并没有类似java等其它语言中的接口类型,但是python中 ...

  4. SpringBoot中VO,DTO,DO,PO的概念、区别和用处

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/zhuguang10/article/de ...

  5. 领域驱动模型DDD(一)——服务拆分策略

    前言 领域驱动模型设计在业界也喊了几年口号了,但是对于很多"务实"的程序员来说,纸上谈"术"远比敲代码难得太多太多.本人能力有限,在拜读相关作品时既要隐忍书中晦 ...

  6. Java开发中的几种对象的说明(PO,VO,DTO,BO,POJO,DAO,SAO等)

    一.PO :(persistant object ),持久对象 可以看成是与数据库中的表相映射的java对象.使用Hibernate来生成PO是不错的选择. 二.VO :(value object) ...

  7. Java 中的PO VO DTO BO

    PO 持久对象,数据: BO 业务对象,封装对象.复杂对象 ,里面可能包含多个类:DTO 传输对象,前端调用时传输 :VO 表现对象,前端界面展示. 当你业务足够简单时,一个POJO 也完全当做PO ...

  8. VO,DTO,DO,PO的划分

    实体类(VO,DTO,DO)的划分   经常会接触到VO,DO,DTO的概念,本文从领域建模中的实体划分和项目中的实际应用情况两个角度,对这几个概念进行简析. 得出的主要结论是:在项目应用中,VO对应 ...

  9. 【Python之路】特别篇--基于领域驱动模型架构设计的京东用户管理后台

    一.预备知识: 1.接口: - URL形式 - 数据类型 (Python中不存在) a.类中的方法可以写任意个,想要对类中的方法进行约束就可以使用接口: b.定义一个接口,接口中定义一个方法f1: c ...

  10. 领域驱动模型DDD(三)——使用Saga管理事务

    前言 虽然一直说想写一篇关于Saga模式,在多次尝试后不得不承认这玩意儿的仿制代码真不是我一个菜鸟就能完成的,所以还是妥协般地引用现成的Eventuate Tram Saga框架(虽然我对它一直很反感 ...

随机推荐

  1. Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!

    在众多开源项目中,高颜值.功能强大且部署简单的项目往往更能俘获开发者的心.然而,实际部署 Web 应用时,面对数据库.缓存.消息队列等复杂的依赖关系,常常令人头疼.Docker 的开源为我们普及了容器 ...

  2. 开箱即用的go-zero示例

    一.概述 开箱即用的 go-zero 示例,内置 api.scheduler.queue.script 服务. 框架初始版本基于 go-zero 框架的 1.5.5 版本,后续会参考 go-zero ...

  3. PanWeiDB2.0异构数据库访问测试

    PanWeiDB2.0异构数据库访问测试 异构数据库访问兼容性测试一览表 No 访问路径 多维度结果 备注 1 PanWeiDB(集中式)-访问-PanWeiDB(集中式) √ 支持复杂SQL 2 P ...

  4. vue强制刷新页面

    方法一 this.$router.go(0) // 会出现一段空白页,用户体验不好 方法二 在 app.vue 中定义 reload() 方法 <template> <div id= ...

  5. 栈的应用(后进先出 LIFO)--括号匹配问题

    博客地址:https://www.cnblogs.com/zylyehuo/ # -*- coding: utf-8 -*- class Stack: def __init__(self): self ...

  6. DNS+scapy学习

    DNS前置知识 大部分介绍转自这篇文章. 官方解释: DNS ( Domain Name System ,域名系统) ,因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联 ...

  7. 修改 Proxmox VE 6.0 LVM Thin 为存储分区

    PVE 安装后默认将 60G 的 SSD 分为了 14G 和 26G 的两个分区,其中 25G 为 LVM Thin,用于ISO镜像存储的分区为 14G,明显不够用,传一个 WInServer2016 ...

  8. 实现领域驱动设计 - 使用ABP框架 - 领域逻辑 & 应用逻辑

    领域逻辑 & 应用逻辑 如前所述,领域驱动设计中的业务逻辑分为两部分(层):领域逻辑和应用逻辑: 领域逻辑由系统的核心领域规则组成,应用逻辑实现应用特定的用例 虽然定义很明确,但实现起来可能并 ...

  9. windows 本地部署DeepSeek

    一:前言: 那么为什么要本地部署,主要就是企业或者个人为了数据安全和防止受限网络等其 数据安全:数据不用上传到外面,在本地处理,不用担心数据泄露,像金融.医疗这些对数据安全要求高的行业特别需要. 功能 ...

  10. 2024 蓝桥杯模拟赛3(div1+div2)

    2024 蓝桥杯模拟赛3(div1+div2) P8834 [传智杯 #3 决赛] 序列 简单的模拟,数据范围很小,暴力即可 点击查看代码 #include <bits/stdc++.h> ...