Appearance
领域驱动设计在教育业务线索管理中的实践
看在前面
一、项目背景
教育领域完整的流程板块包括:招生拓客、线索管理、教务管理、学员管理、互动督学、口碑传播。
招生拓客环节:通过线上营销工具或线下地推收集潜在学员的线索信息,录入线索管理系统;
线索管理环节:用线索资源管理系统对收集的线索做统一管理。将潜在学员转为真正的学员,提供给后续教务管理使用。
可见线索管理在整个教育链路中承担承上启下的作用。该项目分为两大业务域:
线索域:负责线索收集、线索管理(新增/更新、查询、分配、跟踪、放弃)这类功能;
配置中心域:管理公共配置资源,如线索关联的标签、来源。
二、领域驱动基础概念
为什么要用DDD
非 DDD 思路下,通常先设计数据库表,再由表结构推导实体对象。这类对象只是数据载体、没有行为。开发过程是面向过程的、以数据为中心的。采用 DDD 则是建立基于面向对象设计的系统。
2.1 领域驱动设计标准分层架构(四层模型)
用户界面层(展示、请求数据、发送命令)
应用层(业务用例的编排和组装)
领域层(业务逻辑核心:领域模型 + 领域服务)
基础设施层(消息发送、领域持久化等技术能力)(1)基础设施层:为其他层提供通用技术能力。实际项目中主要用于持久化数据的读写。把领域对象序列化到 MySQL、HBase、MongoDB、ES 这类存储介质,或反向取出并组装成领域对象。一般采用仓储机制实现领域持久化。
(2)领域层(模型层):业务系统最核心的一层,几乎所有业务逻辑都在这里实现。包含:
领域模型:抽象复杂业务逻辑为便于理解的概念图模型,由实体和值对象构成。与数据模型的区别:数据模型描述对象的持久化方式。领域模型表述领域中各类及各类之间的关系;
领域服务:领域模型的补充。一些概念本质是操作,会涉及多个领域对象并协调它们完成。若强行归入某个对象,会导致职责不明确。例如线索详情页由"线索基础信息、标签信息、来源信息、线索处理日志信息"构成。建模为四个独立实体后,需要解决完整线索信息的聚合问题。于是引入领域服务承载线索信息聚合操作。
(3)应用层:提供应用服务,负责业务用例的编排和组装。与领域服务的主要区别(作者观点):是否处理业务逻辑。对外为用户界面层提供应用功能,对内调用领域对象或领域服务完成编排。
(4)用户界面层:负责用户信息展示、请求数据、发送命令。实际可以不存在。项目早期通过 REST 服务与前端交互。后来改用 RPC,在接口层声明二方服务接口与前端 Node 层交互,应用层做具体实现,弱化了该层。
(5)工程结构:线索管理应用的模块划分与 DDD 分层对应关系:
| DDD 分层 | 工程模块 | 职责 |
|---|---|---|
| 用户界面层 | demo-web、demo-api | REST 接口 / 二方服务接口声明 |
| 应用层 | demo-biz(api) | 应用服务,接口的具体实现 |
| 领域层 | demo-biz(domain)、demo-domain、demo-dependency | 领域 model、仓储接口定义、外部系统调用封装 |
| 基础设施层 | demo-dal | 数据持久化 |
2.2 需求分析利器——四色原型图
简单需求用用例图,复杂些附加时序图、状态图。业务非常复杂时可用四色原型分析模式分析业务行为、参与对象、对象关系。四个构成元素:
时刻-时间段原型(Moment-Interval,MI):某个时刻或某段时间内发生的事。如租房合同签署(有发生日期、行为人),粉红色表示;
参与方-地点-物品原型(Part-Place-Thing,PPT):参与活动的人或物及发生地点。如合同(物)、承租人(人)、中介办公室(地点),绿色表示;
描述原型(Description,DESC):对 PPT 公共属性的描述,如合同中的租期、租金、押金、违约条件这类约定,蓝色表示;
角色原型(Role):即"身份",如承租人和中介工作人员,黄色表示。
一句话概括:一个什么样的人或物,以某种角色,在某个地点,参与某个活动。活动发生在某个时刻或某段时间内。对应关系:"什么样的"是 DESC,"人或物/地点"是 PPT,"角色"是 Role,"某时刻/时间段内的活动"是 MI。
2.3 DDD几个核心领域概念
实体:具有身份和连贯性的概念。特征:是数据(属性)和行为(业务逻辑)的结合体。有唯一标识,两个对象唯一标识相等即为同一实体。其他属性不等只表示同一实体生命周期中的不同阶段。唯一标识属性值不可变。
例如精选内容平台中每篇"博文"是一个实体。博文 id 为唯一标识。拥有属性(标题、作者、发表时间、内容)和行为(更新、删除、关联导购商品)。
值对象:作为属性存放于实体内部。无需唯一标识,相等判断依据内部所有属性值是否相等。属性值不可变,改变需删除重建新对象。例如"置顶的留言"可定义为值对象放在博文实体中,变化时重建并重新赋值。
聚合:一组具有内聚关系的领域对象(实体和值对象)的集合。每个聚合有一个根实体(聚合根),外部对象必须先访问聚合根才能访问聚合内实体。例如博文包含基础信息、关联商品信息、关联标签信息,构成一个聚合,"博文基础信息"为聚合根。
仓储(Repository):领域对象在内存中活动后需要持久化,重建对象时需按当前状态重建。过程中要频繁与数据库打交道。仓储就是提供管理领域对象及持久化机制的组件。
特征:连接领域层与基础设施层的桥梁。接口定义放领域层、实现放基础设施层,解耦领域层与 ORM。仓储存储的对象一定是聚合,只对聚合设计仓储。更新、删除操作以聚合为单位。
三、线索资源管理DDD实战
结合四色原型图设计领域模型的步骤:
根据需求,采用四色原型分析法建立初步领域模型;
分析领域模型,识别实体、值对象、领域服务;
对实体、值对象关联聚合,提炼聚合边界和聚合根;
为聚合根设计仓储(一般一个聚合一个仓储)。思考实体、值对象的创建方式(工厂或构造函数);
走查需求场景,验证领域模型合理性。
(1)场景分析提炼四色原型图(线索域五个用例):
新增/更新线索:仅高级管理员、课程顾问、普通管理员有权限。参与方是商家,角色为上述三种。物品是线索(由线索基础信息、线索标签、线索来源构成)。活动是"新增/更新线索";
查询线索:同上角色与物品原型,活动是"查询线索";
分配线索:线索需跟进时必须分配跟进人,跟进人无法完成可转让,活动是"分配线索";
跟踪线索:课程顾问跟踪并记录跟踪记录,物品原型是跟踪记录,活动是"添加跟踪记录";
放弃线索:课程顾问觉得线索难跟进可放弃,活动是"放弃线索"。
(2)识别实体、值对象、领域服务、聚合。原型与 DDD 的映射:PPT 对应实体。Role 是实体在不同状态下的表现,放于实体中构成带状态实体。DESC 对应值对象。MI 间接对应领域服务。
原型图中有"商家、线索基础信息、跟踪记录、来源信息、标签信息"5 个 PPT,可定义 5 个实体。"高级管理员、课程顾问、普通管理员"是商家的不同身份。用一个标识符描述即可。
(3)聚合边界分析:线索是核心,ClueEntity 与 SourceEntity、RecordEntity、TagEntity、UserEntity 相关联,后四者之间无联系。
ClueEntity 与 UserEntity:线索创建之初可以没有跟进人,跟进过程中强制绑定跟进人。用户脱离线索没有存在价值,只是线索的归属属性。因此把 UserEntity 改名为 UserVO,作为值对象放在 ClueEntity 内,线索实体做聚合根;
ClueEntity 与 Source/Tag/Record 三者,从两方面判断是否聚合:
聚合代表完整概念、内部一致性。聚合内对象要么一起获取/更新/删除。保存时任一对象被修改,都应视为聚合被修改。在保证合理性的前提下应尽量设计小的聚合。线索管理人员会频繁关联标签、来源、跟进记录。从内部一致性角度看,分开更好;
聚合根与对象间要保持不变性——对象间存在某种不变规则。ClueEntity 与三者间不存在这种不变性。任意来源/标签/跟踪记录必有一条对应线索。但一条线索可以没有来源、标签、跟踪记录。三者均可在各自领域被单独访问。
策略:SourceEntity、TagEntity、RecordEntity 各自定义为一个聚合,本身作为聚合根。查询线索详情时的信息聚合,交给领域服务完成。
(4)仓储定义:一个聚合对应一个仓储:
| 仓储 | 聚合 | 聚合根内对象 |
|---|---|---|
| ClueRepository | ClueAggregate | ClueEntity、UserVO |
| SourceRepository | SourceAggregate | SourceEntity |
| TagRepository | TagAggregate | TagEntity |
| RecordRepository | RecordAggregate | RecordEntity |
四、总结与思考
本文从"线索资源管理"实际项目出发。阐述从需求分析到方案设计阶段,如何采用 DDD 思想提炼领域模型。路径:先讲项目背景与业务场景,再讲 DDD 分层结构、四色原型分析法与核心领域概念。最后结合场景一步步提炼出领域模型(实体、值对象、聚合、仓储)。
核心启示:先用四色原型把业务语言映射为对象语言。再依据"内部一致性 + 不变性"划聚合边界,聚合宁小勿大。跨聚合的信息组装交给领域服务。
内容来源:原文 · 2026-10 整理回填。