DDD之值对象的理解

317 阅读2分钟

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