DDD 中的值對象和實體
-
背景
-
定義
-
舉例說明
-
總結
背景
在 DDD 中有兩個比較重要的對象,即值對象和實體。而聚合根就是由這兩個對象組成的,所以業務建模前我們都會先定義好實體和值對象,然後再構建聚合根,所以再研究複雜的聚合根之前我們先來研究相對簡單但是基礎的值對象和實體吧。
定義
-
實體:實體以 DO(領域對象)的形式存在,擁有唯一標識符,且標識符在歷經各種狀態變更後仍能保持一致 (唯一標識)。實體類通常採用充血模型,與這個實體相關的所有業務邏輯都在實體類的方法中實現。簡單來說就是有唯一標識 + 業務行爲方法。
-
值對象:與實體相對應的就是值對象,如果沒有唯一標識就是值對象。值對象一般是嵌套在實體裏面的。嵌套方式可能有兩種,一種是直接嵌套整個 Java 對象,二是嵌套一個 json 對象。其次值對象是不會改變的
舉例說明
拿常見的電商項目來說,每個用戶一般會有一個唯一標識比如身份證。或者唯一 id,而用戶會有收貨地址,收貨地址是沒有唯一標識的,是依賴實體而存在的,沒有用戶地址也就失去了存在的意義。所以收貨地址是值對象。
兩者對應的關係大致是如下
在我們構建值對象的時候,一般都是會使用 Builder 模式去構建值對象,然後不暴露 set 方法,原因如下:在傳統通過 new 構造對象,然後各種 set 方法,在我們出現 bug 或者一些業務排查的時候,整個對象在各種地方 set 了屬性,我們無法準確定位到對象的某個屬性在哪個時候悄悄被改變了,排查起來特別困難,而值對象一般是不可變類似一種配置的概念,正好特別適合這種方式去構造。但是這種方式也會有一定缺陷,比如某些三方框架都會調用無參構造方法去初始化,然而使用了 Builder 模式私有化了構造方法,就會有意想不到的報錯,但這種錯誤一般在我們的可控範圍,所以具體是否使用這種方式去構造實體也是自己在落地 DDD 去考慮,但是不用強制去執行,建議靈活應用。畢竟 DDD 在所有人的理解中都不太一樣,團隊中使用起來覺得好用合適纔是最好的。
總結
實體和值對象有時候很容易區分,有時候又不太容易區分,不過主要還是看有沒有唯一標識,如果有唯一表示就是實體,如果能夠獨立存在也是實體,否則則是值對象,比如像上面的地址,如果脫離了用戶其實就沒有實際意義了。上面的實體和值對象是我自己的理解,如果覺得有什麼偏差歡迎大家補充。期望在 DDD 的設計上與大家共同進步。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/LFJXMlcTBbyfCr85SVozag