106 lines
3.8 KiB
Markdown
106 lines
3.8 KiB
Markdown
---
|
||
title: 领域驱动设计
|
||
categories:
|
||
- CS
|
||
status: doing
|
||
abbrlink: 31204
|
||
---
|
||
|
||
|
||
# 参考文献
|
||
|
||
- [蚂蚁金服数据体验技术团队 - 领域驱动设计](https://juejin.cn/post/6844903618680881165)
|
||
- [美团 - 领域驱动设计在互联网业务开发中的实践](https://tech.meituan.com/2017/12/22/ddd-in-practice.html)
|
||
- [领域驱动实战思考](https://huhao.dev/posts/61190ae2/#%E9%97%AE%E9%A2%98%E5%AD%90%E5%9F%9F%E8%AF%86%E5%88%AB)
|
||
- [基于 DDD 的前端项目架构设计与实战](https://www.tangshuang.net/8663.html)
|
||
- [React 语境下前端 DDD 的思考](https://www.tangshuang.net/8212.html)
|
||
|
||
# 架构对比
|
||
|
||
从后端视角看,对比传统的三层架构,领域驱动
|
||
|
||
- `充血`复用了:领域对外的接口
|
||
- `领域服务`封装了:领域之间的联系
|
||
|
||
贫血模型->充血模型,降低了`service层`的负担,同时保证了业务迭代,`entity`的独立性
|
||
|
||
## MVC
|
||
|
||
从数据库视角、分析实体出发,进行系统的构建
|
||
|
||
- DAO 层
|
||
- Service 层
|
||
- Controller 层
|
||
|
||
## 后端 DDD
|
||
|
||
> 针对基础设施层,也可以考虑加入`防腐层`、`工厂`
|
||
|
||
一个领域基本四层架构
|
||
|
||
1. 用户层(user interface): 对标 controller,对外提供 web 服务、接口
|
||
2. 应用层(application): 业务层,定义领域可以解决的问题 `domainService`
|
||
3. 领域层(domain): 纯粹的描述业务实体
|
||
4. 基础设施层(infra): 持久化层(Builder+repository)
|
||
|
||
同时,领域拆分带来如下两个致命问题
|
||
|
||
- 领域化(微服务)后,数据库是分开的,导致实体调用链复杂,避免跨库查询
|
||
- 避免分布式事务同步
|
||
|
||
## 前端 DDD
|
||
|
||
> ?? 这里存在一个问题,api 网关到底要不要挪到前端领域目录下来开发
|
||
|
||
1. 用户层: web、mobile、mini-program ...多端
|
||
2. service: 暴露给 UI 组件的 `domainSerivce`,组织实体的状态流转
|
||
3. entity: 实体、聚合实体、事件
|
||
4. infra: api 请求、缓存、工具
|
||
|
||
## 工厂 Factory / Builder
|
||
|
||
- 数据库表设计层面,如果要`多对多`的关系,只能很别扭的设计一个中间表。
|
||
- 实体 A 适合 `mongo`文档形存储,实体 B 适合`mysql`关系型存储。对于 `Builder` 而言,直接在这个领域搓出来 `A 和 B` 的 `CRUD`的实现方法
|
||
|
||
## 防腐层 Facade / Adaptor
|
||
|
||
也被成为适配器,隔离第三方/外部服务,例如场景,用户上传文件到阿里云、腾讯云
|
||
|
||
```js
|
||
class UserUploadServiceFacade extends UserService {
|
||
/**
|
||
* 上传
|
||
*/
|
||
async upload(oss) {
|
||
if (oss === "ali") return "OK";
|
||
if (oss === "tx") return "FAIL";
|
||
}
|
||
}
|
||
```
|
||
|
||
# 领域模型
|
||
|
||
实体的`贫血->充血`是一个随着业务发展过程演变的结果,初期业务场景不明确,很难充血,瞎几把充血,纯属找难受。
|
||
|
||
是否需要引入`聚合根(aggregate root)`的概念,解决领域内实体独立、平铺关系带来的不方便,这个可能比较看心情
|
||
|
||
## 贫血模型(POJO)的问题
|
||
|
||
> 脱离了业务复杂度谈分层,好比抛开剂量谈毒性
|
||
|
||
领域对象里只有`get/set`方法,所有的业务逻辑都不包含在内,从而造成`失忆症`,从实体中,无法知道发生了那些业务,需要去 `service层` 里挨个梳理,一旦业务迭代、`service 层`直接开始变成屎山
|
||
|
||
## 充血模型 && 领域服务的关系
|
||
|
||
> 确保领域之间独立的,随着不断的充血,保证领域(实体)是独立发展的
|
||
|
||
假定两个 domain(实体):
|
||
|
||
- 学生: 上课、做作业
|
||
- 老师、全体起立、布置作业
|
||
|
||
假定`老师`调用`全体起立`,对应肯定要`学生`调用`上课`,这个就是 `领域服务(domainService)` 需要去处理的,他俩不能建立直接的联系。
|
||
|
||
- 增加新的业务逻辑:在 `domainService` 增加新的方法。
|
||
- 调整旧的业务逻辑:修改`学生`,`老师`,内部具体的方法,`domainService` 完全不需要变化。
|