DDD 把领域对象分成了两种:一种是实体,另一种是值对象。前面我们讨论的组织、员工等等都是实体。而值对象则往往是用来描述实体的属性“值”的。值对象在一些方面和实体有明显的区别,但在 DDD 提出以前,人们建模的时候,一般都只重视实体,对值对象的研究不够。DDD 强调实体和值对象的区别,可以让领域建模更加准确和深入。
之前的员工状态转换代码是后面这样
// imports ...
public class Emp extends AggregateRoot {
// 其他属性 ...
protected EmpStatus status;
//其他方法 ...
public Emp becomeRegular() {
onlyProbationCanBecomeRegular();
status = REGULAR;
return this;
}
public Emp terminate() {
shouldNotTerminateAgain();
status = TERMINATED;
return this;
}
private void onlyProbationCanBecomeRegular() {
if (status != PROBATION) {
throw new BusinessException("试用期员工才能转正!");
}
}
private void shouldNotTerminateAgain() {
if (status == TERMINATED) {
throw new BusinessException("已经终止的员工不能再次终止!");
}
}
}
现在我们把规则校验移到员工状态(EmpStatus)里面
package chapter18.unjuanable.domain.orgmng.emp;
// imports ...
public enum EmpStatus {
REGULAR("REG"), // 正式
PROBATION("PRO"), // 试用期
TERMINATED("TER"); // 终止
private final String code;
EmpStatus(String code) {
this.code = code;
}
public String code() {
return code;
}
//其他方法 ...
public EmpStatus becomeRegular() {
if (this != PROBATION) {
throw new BusinessException("试用期员工才能转正!");
}
return REGULAR;
}
public EmpStatus terminate() {
if (this == TERMINATED) {
throw new BusinessException("已经终止的员工不能再次终止!");
}
return TERMINATED;
}
}
采用了新的员工状态的员工类,就可以改成后面这样了
package chapter18.unjuanable.domain.orgmng.emp;
// imports ...
public class Emp extends AggregateRoot {
// 其他属性 ...
protected EmpStatus status;
//其他方法 ...
public Emp becomeRegular() {
status = status.becomeRegular();
return this;
}
public Emp terminate() {
status = status.terminate();
return this;
}
// 删除了 onlyProbationCanBecomeRegular()
// 删除了 shouldNotTerminateAgain()
}
现在,Emp 自己不再校验这两条业务规则了,而是委托给了 EmpStatus,程序变得更加简洁。 由此可见把值对象单独管理的好处。
极客时间《手把手教你落地DDD》第18课学习笔记 Day18