天天看點

DDD領域驅動設計實戰(三)-深入了解實體(下)5 建立實體

5 建立實體

建立一個實體時,我們總期望通過構造器就能初始化足夠多的實體狀态,因為這樣更容易通過各種條件查找到該實體。

在使用及早生成唯一辨別的政策時,構造器至少需接受唯一辨別參數。若還有可能通過其他方式查找實體,比如名字或描述資訊,那應該将這些參數一并傳給構造器。

有時一個實體維護一或多個不變條件(Invariant,在整個實體生命周期中都必須保持事務一緻性的一種狀态) 。

不變條件主要是聚合所關注的,但聚合根也是實體。

如果實體的不變條件要求該實體所包含的對象都不能為null或必須由其他狀态計算所得,那麼這些狀态也需作為參數傳遞給構造器。

public class User extends Entity {
    ...
    // 每一個User對象都必須包含tenantld、username, password和person屬性。
    // 即在User對象得到正确執行個體化後,這些屬性不能為null
    // 由User對象的構造器和執行個體變量對應的setter方法保證這點
    protected User (Tenantld aTenantld
                    String aUsername,
                    String aPassword,
                    Person aPerson) (
        this();
        this.setPassword(aPassword);
        this.setPerson(aPerson);
        this.setTenantld(aTenantld);
        this.setUsername(aUsername);
        this.initialize();
    }
    ...
    protected void setPassword(String aPassword) { 
        if (aPassword == null) {
            throw new 11legalArgumentException(
                "The password may not be set to null.");
        )
        this.password = aPassword;
    )
    
    protected void setPerson(Person aPerson) (
        if (aPerson == null) ( 
            throw new IllegalArgumentException("The person may not be set to null.");
        }
        this.person = aPerson;
    }
    
    protected void setTenantld(Tenantld aTenantld) ( 
        if (aTenantld == null) {
            throw new IllegalArgumentException("The tenantld may not be set to null."); 
        }
        this.tenantld = aTenantld;
    }
    protected void setUsername(String aUsername) (
        if (this.username != null) {
            throw new IIlegalStateException("The username may not be changed.n);
        }
        if (aUsername == null) {
            throw new IllegalArgumentException("The username may not be set to null."); 
        }
        this.username = aUsername;
    }         

User對象展示了一種自封裝性。在構造器對執行個體變量指派時,把操作委派給執行個體變量對應的setter方法,便保證了執行個體變量的自封裝性。執行個體變量的自封裝性使用setter方法來決定何時給執行個體變量指派。

每個setter方法都“代表着實體”對所傳進的參數做非null檢查,這裡的斷言稱為守衛(Guard)。setter方法的自封裝性技術可能會變得非常複雜。是以對于複雜的建立實體場景,可使用工廠。

User對象的構造函數被聲明為 protected。 Tenant實體即為User實體的工廠也是同一個子產品中唯一能夠通路User 構造器的類。這樣一來,隻有Tenant能夠建立User執行個體。

public class Tenant extends Entity {
    // 該工廠簡化對User的建立,同時保證了Tenantld在User和Person對象中的正确性
    // 該工廠能夠反映通用語言。
    public User registerUser(String aUsername,
                             String aPassword,
                             Person aPerson) {
        aPerson.setTenantld(this.tenantld());
        User user = new User(this.tenantld(), aUsername, aPassword, aPerson);
        return user;
}      

參考

https://tech.meituan.com/2017/12/22/ddd-in-practice.html

《實作領域驅動設計》

實體和值對象:從領域模型的基礎單元看系統設計

https://blog.csdn.net/Taobaojishu/article/details/106152641

繼續閱讀