Skip to content

领域模型与数据模型的边界 ​

看在前面 ​

领域模型和数据模型是两个很容易被混淆的概念。很多人在系统设计时会不自觉地用其中一个代替另一个。结果要么把系统做复杂了,要么把系统做"傻"了。本文讲清楚两者的区别、错误用法以及正确的使用姿势。

概念区别 ​

数据模型:用来描述数据在数据库/存储中的组织形式,是从"存储视角"出发的模型。常见形式就是二维表(关系型数据库)。设计原则一般是三范式(3NF):字段原子性、消除部分依赖、消除传递依赖。它关心的是数据不冗余、一致性、查询效率。

领域模型:对领域内的概念类或现实世界中对象的可视化表示,是"业务视角"的模型。它描述业务概念、业务状态和业务规则。领域模型关心的是业务语义是否表达清楚。常用 UML 类图表达,又称为概念模型、领域对象模型、分析对象模型。

一句话总结:数据模型面向存储,领域模型面向业务。

用法区别(示例) ​

以"营销活动"为例:

  • 数据模型:campaign 表,字段 id、name、status、budget、start_time、end_time……强调的是这些字段怎么存;

  • 领域模型:活动(聚合根)、预算(值对象)、活动状态机、规则对象(预算耗尽自动结束)。活动状态机是草稿→提交审核→发布→暂停→结束。强调的是活动这个业务概念有哪些行为和不变量(比如已结束的活动不能再修改预算)。

关键差异:

  • 数据模型没有行为,只是数据的载体;领域模型是数据 + 行为,是"有血有肉"的对象;

  • 数据模型优化目标是存储与查询;领域模型优化目标是业务逻辑的内聚与表达;

  • 同一个业务概念在数据模型里可能是一张表,在领域模型里可能是一个聚合(多张表 + 多个对象)。

错误用法一:用领域模型代替数据模型 ​

典型表现:设计好领域模型后直接拿类结构当表结构建库(或直接用 NoSQL 文档存储领域对象)。

问题:

  • 领域对象为了表达业务会包含大量对象引用、集合、继承层次,直接存储会导致表结构极不合理;

  • 破坏 3NF,产生大量冗余,更新异常频发;

  • 查询性能失控——按对象图存储后,报表类查询、跨对象统计变得极其低效,无法做查询优化;

  • 数据库层面的约束(外键、唯一索引、默认值)没法落地。

本质:这是把"业务视角"强行塞给"存储视角",存储层被迫理解业务。

错误用法二:用数据模型代替领域模型 ​

典型表现:表设计好之后,用代码生成器生成实体类(PO/DO),Service 里直接操作这些纯数据类写业务逻辑。

问题:

  • 实体类只有 getter/setter,没有业务行为——贫血领域对象(Anemic Domain Object);

  • 业务规则全部泄漏到 Service 层,Service 越来越胖,成为"事务脚本";

  • 业务概念在代码里消失,读代码必须人肉把 if/else 翻译回业务语言;

  • 领域"失忆症":换个人接手,无法从代码中还原业务规则。

本质:这是把"存储视角"强行塞给"业务视角",业务逻辑无处安身。

那到底应该怎么用? ​

顺序上:先领域模型,后数据模型。

  1. 和业务专家沟通,用领域模型(类图 + 用例)把业务概念、规则固化下来;

  2. 再根据领域模型推导数据模型。同时结合查询场景、数据量做反范式、分表这类存储优化;

  3. 两者允许不一致:一个聚合可能拆成多张表。一张表也可能被多个聚合共享(只读)。

代码上:领域对象与数据对象分离,通过 ORM/转换层映射。

常见分层(参考阿里巴巴 Java 开发手册的 DO/DTO 概念):

  • DO(Data Object)/ PO(Persistent Object):与表结构一一对应,仅作持久化载体;

  • 领域对象(Entity/ValueObject/Aggregate):携带业务行为,内存中活动;

  • DTO(Data Transfer Object):对外的传输对象,隔离领域对象不直接出边界。

外部请求 <-> DTO <-> [领域对象(业务行为)] <-> DO/PO <-> 数据库
                         |
                    Repository 做对象转换

Repository 的职责之一就是在领域对象与数据对象之间做双向转换。查库时把 DO 组装成领域对象,保存时把领域对象拆解为 DO。

小结 ​

  • 数据模型面向存储、三范式、表结构;领域模型面向业务、类图、行为与规则;

  • 用领域模型代替数据模型 → 存储失控;用数据模型代替领域模型 → 贫血与失忆;

  • 正确姿势:先领域后数据,两层各自演进,用 DO/PO + Repository 转换层隔离;

  • 小系统可以简化(DO 直接当领域对象用),但业务复杂度上来后,这套分离是保持代码可演进的护栏。

内容来源:原文 · 2026-10 整理回填。