【java】详解Entity 、DTO 、 VO : 如何区分,如何使用

2,641 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天。

1.DTO

DTO(Data Transfer Object)是数据传输对象,主要用来在不同的应用层之间传输数据。  可以把 DTO 当作是没有逻辑的数据容器。DTO 这个概念最初是由Martin Fowler 在他的《企业应用架构模式》一书中定义的。

2.Entity

通常在我们的领域层,会有实体类 Entity。关于 Entity,在不同的上下文有不同的涵义,大概有两种声音:

  1. 在 java ee 和 jpa 相关的上下文中: Entity 与数据库表映射,表示数据库中持久化的数据。对于这种场景,Entity 似乎就和 DTO 看起来没有什么区别了,这也就是令人产生困惑的地方。
  2. 在领域驱动设计 DDD 上下文中:Entity 是领域模型中的重要概念,不仅有属性,还有与Entity 想关的封装了业务逻辑的行为(方法)

但是不管是 jpa 中的Entity,还是DDD 中的 Entity,都会映射到数据库表。它们的适用的场景都是和 DTO 不同的。DTO 是用来在不同的层传输数据用的,所以 DTO 应该只包含某个接口参数或者返回值需要的字段数据,可以是与数据库表字段相同,也可以相差很大,甚至聚合了多个数据库表的信息。

有些项目直接将实体类用作 API 输出、视图数据、查询结果或作为系统各部分之间交换信息。这通常会造成领域层 Entity 与调用方耦合,为了维持接口兼容性,导致领域层难以按照自己的迭代更新。当需要传输的信息只有Entity 的部分属性时,也会导致传输过多不需要的冗余信息。

3.VO

这里讨论的 VO 是 View Object,表示显示层对象。显示层对象,通常是 Web 向模板渲染引擎层传输的对象(摘自《阿里巴巴 Java 开发手册1.4.0》)。

与 DTO 一样,VO也是数据传输对象,是专门用于显示层与前端的数据传输对象。对于很多业务逻辑比较简单的请求处理,通常请求会已相同的粒度从前到后穿过各层。我们会发现VO 和 DTO 属性一模一样。而且我们还得将请求VO 转换成 DTO,将相应的DTO 再转换成响应VO。 为什么不直接使用 DTO 呢?对于这种逻辑不复杂的 CRUD 业务 只有 DTO 通常是没有问题的。

也存在有些场景,显示层会有些特殊的显示逻辑的要求。比如某些属性在显示层不展示、数据中用 0/1 表示的性别,在显示层需要“女/男”。由于接口一旦发布,为了保证兼容接口的客户端,就比较难以更改。出于对接口稳定性考虑,在显示层使用区别于 DTO 的显示层对象(VO),尽管大多数时候它们没有区别。