Clean Architecure
干净框架,总体上分为
- 实体层(Entities)
- 用例层(Use Cases)
- 接口适配层(Interface Adapters)
- 框架驱动层(Frameworks & Drivers)
其中,依赖自外向内流动
综述
┌────────────────────────────┐
│ Frameworks & Drivers │
│ (配置、DB 驱动、HTTP Server) │
└─────────────┬──────────────┘
↓
┌────────────────────────────┐
│ Interface Adapter s │
│ (Controllers, Repos, DTO) │
└─────────────┬──────────────┘
↓
┌────────────────────────────┐
│ Use Cases │
│ 业务流程 Port 接口和测试 |
└─────────────┬──────────────┘
↓
┌────────────────────────────┐
│ Entities │
│ 领域模型 聚合根 规则 │
└────────────────────────────┘
实体层
最内层的层级,包含了领域模型,聚合根和一些其他逻辑。它是最“纯粹”的模块,应当与其他模块和外部依赖无关。 主要 ——
- 领域实体(核心业务对象):在学生管理系统中定义“学生模型”
- 值对象(不带身份标识、不可变的小对象):订单管理系统中的”货币“、学生签到的“日期”
- 聚合根(领域实体和值对象作为一个聚合整体进行管理):订单管理系统中的“仓库”(是若干订单的集合)
- 领域事件(领域内重要事态的发生):订单生成,订单取消等
- 领域服务(将跨实体的业务逻辑抽象成无状态服务接口):订单计算优惠(涉及订单和价格等多个实体)
- 方法签名应只接收所需的实体和值对象
- 业务规则跨越实体边界,无法在单个实体内部完成校验或流程
用例层
框架中的第二层,用例层把业务流程集中管理 —— 相当于军师指挥军队一样,把这些规则按「谁在什么时候做什么」的顺序串联起来。 同时处理输入输出、事务边界、异常传播等 —— 使用端口+模型定义好“进来”和“出去”的接口,并在中间有序地调度领域实体和服务,实现完整的业务流程
有点抽象,举个创建订单的例子:
- 首先在实体层拥有了订单模型等实体
- 接着在用例层进行创建订单等具体逻辑的编排——
- 调用实体层的接口创建订单实体
- 调用实体层的接口进行订单实体的检验
- 调用接口适配层中的接口进行订单持久化操作
NOTE
用例层关注的是我们在什么时候做什么,而具体细节不是这个层级需要考虑的事情(仅调用接口)
接口适配层
和其名字一致 —— 作为Clean Architecture的第二外层,负责把将用例层和外部系统进行数据类型或者协议转化
需要实现的东西 ——
- 数据适配:
- 将外部请求映射成用例层的请求模型
- 将用例层返回的类型转化成外部输出格式
- 接口实现
- 实现用例层的定义的逻辑接口
- 沟通具体的”轮子“接口
- 协议和错误处理
- 把业务中出现的错误转化成外部可识别错误
- 适配HTTP状态码等
DANGER
接口适配器只依赖外部框架和用例层的端口接口,而不依赖业务模型的内部细节(依赖倒置原则)
框架驱动层
最外层,组装依赖、初始化基础设施,以及启动应用 —— 比如书写main function