手把手教你落地 DDD
钟敬
Thoughtworks 首席咨询师、数字化转型与运营团队 DDD 负责人
19697 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 45 讲
AIGC特别策划 (2讲)
结束语&结课测试 (2讲)
手把手教你落地 DDD
15
15
1.0x
00:00/00:00
登录|注册

16|聚合的实现(中):怎样实现不变规则?

你好,我是钟敬。
上节课我们学习了聚合的封装,它的目的是确保不变规则。那么,具体来说,封装是怎样确保不变规则的呢?为回答这个问题,今天我们继续来讨论怎样为聚合实现不变规则。
另外,上个迭代我们说过,仓库(Repository)是以聚合为单位进行持久化的,不过,对这一点,我们之前还没有充分展开。今天,我们也会来实现聚合的持久化,带你理解这个知识点。
此外,完成了添加员工的功能后,我们也会为修改员工功能做一些准备。

实现不变规则

我们首先来实现和改变状态有关的两个规则。
后面是具体的代码。
package chapter15.unjuanable.domain.orgmng.emp;
// imports ...
public class Emp extends AuditableEntity {
// other fields ...
private EmpStatus status;
// other getters and setters ...
public EmpStatus getStatus() {
return status;
}
//转正
void becomeRegular() {
// 调用业务规则: 试用期的员工才能被转正
onlyProbationCanBecomeRegular();
status = REGULAR;
}
//终止
void terminate() {
// 调用业务规则: 已经终止的员工不能再次终止
shouldNotTerminateAgain();
status = TERMINATED;
}
// 实现业务规则
private void onlyProbationCanBecomeRegular() {
if (status != PROBATION) {
throw new BusinessException("试用期员工才能转正!");
}
}
private void shouldNotTerminateAgain() {
if (status == TERMINATED) {
throw new BusinessException("已经终止的员工不能再次终止!");
}
}
}
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了如何实现聚合的不变规则,主要包括封装和持久化两个方面。作者首先讨论了与状态变化相关的规则,如转正和终止员工的规则,以及关于技能和工作经验的不变规则。强调了业务规则必须在领域层实现,并且应该直接在聚合根里实现,以确保规则不被破坏。文章还介绍了使用装配器进行领域对象和DTO之间的转换,与之前的工厂模式进行了比较。作者分析了工厂和装配器的利弊,指出装配器可以使用应用层定义的DTO,使代码更加简洁。最后,提醒团队应该统一选择一种实现方式,并根据项目情况和团队偏好进行选择。文章深入浅出地介绍了聚合的不变规则实现方法,对于需要了解聚合实现的读者具有一定的参考价值。文章还讨论了持久化聚合的方法,包括使用仓库将聚合保存到数据库以及标记领域对象的修改状态。整体而言,本文对聚合的不变规则和持久化问题进行了深入探讨,为读者提供了宝贵的技术参考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《手把手教你落地 DDD》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(15)

  • 最新
  • 精选
  • 李威
    置顶
    请教钟老师,持久化“员工聚合”的方法(EmpRepositoryJdbc.save(Emp emp))中会存在性能问题不,比如员工有10个技能,10条工作经验,10个岗位(这个数量级在现实中应该还算是合理的),要保存员工记录再加上这30条记录,那这一个持久化操作就会产生31条 insert into 的 sql 语句,数据库压力会不会太大。 另外,以后如果再增加员工兴趣啊,员工荣誉证书啊,员工职业资格证书啊,等等,那这个“员工聚合”的持久化操作可能就要上百条 insert into 的 sql 语句了,这个怎么解。 当然,确实可以优化一下持久化的方法逻辑,比如将所有 insert 语句组成一条批量 insert 语句,这样所有数据的保存就一条 insert 语句搞定了。但是随着不断在“员工聚合”中添加要保存员工兴趣之类的需求,那这个“员工聚合”的持久化以及数据库查询操作所涉及的数据可能都会比较多,这里会不会是个性能隐患。

    作者回复: 这是个典型问题,非常好。如果真的发展成你说的样子,建模成一个大聚合就不合适了。可以考虑把“工作经验集合”本身作为一个聚合。这样把聚合拆开。

    2023-01-12归属地:湖南
    3
    8
  • 1身份证号,在对象内部充血实现检验逻辑即可。根据上面的评论设置员工信息的时候根据身份证号自动装填性别生日等属性也可以写在对象内部,比如如果生日属性为空,根据身份证号自动补全。 2改变员工状态应该放在empHelper,因为员工状态的改变肯定不是员工自己做的,所以放对象内部不合适,是组织调整员工状态,但是组织设置员工状态的职能不属于组织这个对象的主要职能违反单一职责,所以用empHelper,需要调整员工状态的对象,引用这个helper是比较解耦的做法

    作者回复: 第一问,考虑身份证号本身就是领域对象。同样,第二问,考虑员工状态本身就是领域对象。

    2023-01-11归属地:浙江
    2
  • py
    1. 要看怎么校验,如果是非法输入等检验 放在领域对象里,如果要查表检查有效性,要放到领域服务里 2.员工类的领域对象

    作者回复: 1 还有一种选择是把身份证号本身作为一个领域对象,然后把规则放在这个对象自身 2 考虑为员工状态本身建一个领域对象

    2023-02-16归属地:上海
    1
  • escray
    为什么 emp 包是在 orgmng 包的下一层,如果是平级会不会看上去更容易理解? 对于思考题, 1. 如果要对身份证号进行校验,如果只校验格式,那么可以放在实体里面(员工类),如果需要在数据库里面查询是否有重复的情况,那么可以放在领域服务里面? 2. 改变员工状态的业务规则,可以考虑在领域服务中放一个接口,调用员工类中的实现。 看到留言回复里面说到将身份证号和员工状态当做领域对象,一开始感觉这样操作,领域对象好像有点多了,但是后来发现,是为了值对象做引子

    作者回复: 面向对象熟手的一个标志就是会用一些小对象。关于人员和组织的包结构,取决于建模时的模块划分。

    2023-01-30归属地:北京
    1
  • Geek_97eefa
    老师春节会断更吗?

    编辑回复: 编辑代答,春节不断更,但不更新正课,一方面让老师更充分地准备后续内容,一方面也给还没跟上学习进度的同学多点学习时间。春节时,我们会特别策划几期加餐,敬请期待。

    2023-01-12归属地:广东
    1
  • 远天
    钟老师,你好,如果一次性要创建多个聚合根,是一次一次循环地创建吗?

    作者回复: 通常是。想快的话考虑并发。

    2023-09-21归属地:浙江
  • 这个课程有代码仓库地址吗?

    作者回复: https://github.com/zhongjinggz/geekdemo 目前放出了迭代1的,后面的正在逐渐补充

    2023-04-03归属地:广东
  • AngryShoes
    第二条总结: 关于技能和工作经验的两条规则,必须从整个聚合层面才能验证,所以无法在 Skill 和 WorkExperience 两个类内部实现,只能在聚合根(Emp)里实现。 请教下钟老师如果Skill 和 WorkExperience 是业务实体(Entity)的话,校验规则可以放在实体内部吗?

    作者回复: 可以的,前提是这个规则只在本实体内部。

    2023-03-13归属地:湖南
  • acmookey
    说一个不重要的问题,跟着老师的思路敲代码时,发现好像 Emp中判断WorkExperience的时间是否重叠的逻辑貌似有问题,遂百度了一下,这样表达可能会更准确 !( otherStart.isAfter(thisEnd) || otherEnd.isBefore(thisStart) )

    作者回复: 两者逻辑上应该是等价的

    2023-03-05归属地:广东
    2
  • 邓西
    1. 通用的基础方法,可以放在领域服务中,common; 2. 从聚合根Emp移到EmpRepository中,统一管理修改状态和修改动作。

    作者回复: 1 可以考虑建立一个“身份证号”的领域对象,把逻辑放进去 2 考虑一下建立一个“员工状态”的对象,把逻辑放进去

    2023-01-30归属地:四川
收起评论
显示
设置
留言
15
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部