解决业务的逻辑
- 事务脚本
- 将业务逻辑组织成面向过程的脚本的集合。
- 每个请求都有一个脚本
- 适用于简单业务
- 领域模型
- 将业务逻辑组织成具有状态和行为的类构成的对象模型
- 好处
- 每个小类有少量职责,不需完成所有事情。
- 易理解
- 可独立测试
- 更容易扩展
- 每个小类有少量职责,不需完成所有事情。
DDD概念
- 实体
- 具有持久化ID的对象
- 值对象
- 作为值集合的对象
- 可以互换使用
- 举例
- 钱
- 币的种类
- 金额
- 钱
- 作为值集合的对象
- 工厂
- 负责实现对象创建逻辑的对象或方法
- 因为构造函数无法直接完成
- 负责实现对象创建逻辑的对象或方法
- 存储库
- 用来持久化实体的对象
- 封装了访问数据库的底层机制
- 服务
- 实现不属于实体或值对象的业务逻辑的对象
聚合模式
- 将领域模型组织程聚合的集合,每个聚合都是可以作为一个单元进行处理的一组对象构成的图
- 解释
- 聚合由一个实体、一个或多个值对象组成
- 举例
- order聚合(聚合根)
- 派送信息
- value object,值对象
- 付款信息
- 值对象
- 订单内容
- 值对象
- 派送信息
- order聚合(聚合根)
- 聚合代表了一致的边界
- 规则
- 只引用聚合根
- 聚合根是唯一可以由外表类引用的部分
- 聚合间的引用必须使用主键
- 为了松耦合,边界清晰
- 假设订单中用的是客户对象,那么订单对象可以直接调用客户对象的函数,进行客户信息的变更,这样不合理,且耦合
- 举例
- 订单里面存放客户ID,而不是客户的对象
- 易于持久化
- 只更新一个字段
- 对象之间可以相互引用,不会有循环引用问题
- 业务逻辑上也清晰,因为客户并不是属于订单
- 易于持久化
- 订单里面存放客户ID,而不是客户的对象
- 为了松耦合,边界清晰
- 在一个事务中,只能创建或更新一个聚合
- 确保单个事务不超过服务的边界
- 引入问题
- 创建或更新多个聚合的操纵变得复杂
- 可使用Saga解决
- 同一个服务中,维护一致性,还可以在一个事务中更新两个聚合
- 当然,使用的必须是一个数据库
- 创建或更新多个聚合的操纵变得复杂
- 只引用聚合根
领域事件
- 聚合相关的概念
- 聚合在创建时,或发生其他重大改变时所发布的事件
- 什么是领域事件
- 命名时常用过去分词,比如orderCreated
- 通常具有元数据,比如事件ID、时间戳、执行更改的用户的身份
- 通常包含聚合ID
- 事件增强
- 事件接收方如何获取它需要的信息?
- 一、事件接受方从其他服务里面取(比如OrderCreated事件的信息从Order服务取)
- 增加开销
- 二、事件增强
- 事件信息包含了接收方需要的信息
- 一、事件接受方从其他服务里面取(比如OrderCreated事件的信息从Order服务取)
- 优点
- 接收方不需要查询了
- 不足
- 降低稳定性、可维护性
- 修改的时候,包含的信息往往不能满足所有接收方的需要
- 各个接受方可能需要的信息不一样
- 但是很多情况下,事件需要包含的信息是明显的,所以这个缺点比较小
- 修改的时候,包含的信息往往不能满足所有接收方的需要
- 降低稳定性、可维护性
- 事件接收方如何获取它需要的信息?
- 如何发布事件
- 一种方式是调用API
- 不可取。
- 调用API需要参数
- 比如说一个业务触发了事件,在这块逻辑里面就需要显示调用事件函数,且需要补充事件需要的参数
- 函数改变的时候,还要改很多调用的地方
- 业务逻辑与发布事件耦合
- 就是发布事件嵌入到了业务中
- 调用API需要参数
- 不可取。
- 一种方式是依赖注入
- 参考:https://zhuanlan.zhihu.com/p/67032669
- A在逻辑中调用B,那么A依赖B,这个耦合太紧了。那么可以改为A依赖B0(B的父类),而在A的创建或者某个函数中将B传入,也就是注入。这个传B1、B2还是B3呢,可以放在配置里。
- 所以什么时候发布事件,发布什么事件就可以配置到文件中了
- 参考:https://zhuanlan.zhihu.com/p/67032669
- 一种方式是调用API
- 如何可靠的发布事件
- 将发布事件作为本地数据库事务的一部分
- 比如说有一张表专门用来记录发布的事件,那么在业务逻辑的数据库中,加上这个记录表的操作,发布事务与业务逻辑同时成功,同时失败。
- 将发布事件作为本地数据库事务的一部分
- 如何消费事件
- 将事件发送到消息代理,就是mq,比如kafka、rokectMq
- 事件接受方可直接使用事件代理的客户端,接收消息
- 将事件发送到消息代理,就是mq,比如kafka、rokectMq