5 值對象簡化DB的最佳實踐
傳統資料模組化大多根據資料庫範式設計,每個資料庫表對應一個實體,每個實體的屬性值用單列存儲,一個實體主表會對應N個實體從表。
而值對象簡化了DB設計,多采用反範式,值對象的屬性值和實體對象的屬性值儲存在同一DB實體表。
比如人員和位址,要設計實體和資料模型,有如下解決方案:
把位址值對象的所有屬性放入人員實體表,建立人員實體、人員資料表
會破壞位址的業務含義和概念完整性
建立人員和位址兩個實體,同時建立人員和位址兩張表
增加了不必要的實體和表,需要處理多個實體和表的關系,導緻資料庫複雜性劇增
有沒有一種設計可使得業務含義清晰,又不讓資料庫變複雜?綜合以上方案優勢,揚長避短:
領域模組化時,把位址作為值對象,人員作為實體,即可保留位址的業務含義和概念完整性
資料模組化時,将位址的屬性值嵌入人員實體資料庫表,隻建立人員資料庫表。這既可兼顧業務含義和表達,又不會複雜化DB
值對象就是通過該方式,簡化DB設計:
領域模組化時,将部分對象設計為值對象,保留對象的業務含義,同時又減少了實體數量
資料模組化時,我們可以将值對象嵌入實體,減少實體表的數量,簡化DB設計
要發揮對象的威力,就需優先領域模組化,弱化DB作用,隻把DB作為一個儲存資料的倉庫。即使違反DB設計原則,也不必大驚小怪,隻要業務能順利運作,無傷大雅。
分析
雖然優勢是可簡化DB複雜度。但若使用不當,優勢就會成劣勢。是以必須了解值對象的适用場景。
值對象采用序列化大對象的方式簡化DB設計,減少實體表的數量,可簡單、清晰表達業務概念。該方式雖然降低DB設計複雜度,卻無法滿足基于值對象的快速查詢,導緻搜尋值對象的屬性值變難。
值對象采用屬性嵌入的方式提升了DB性能,但若實體引用的值對象過多,則會導緻實體堆積一堆缺乏概念完整性的屬性,這樣值對象就會失去業務含義,操作也不友善。
是以對照優劣勢并結合實際業務場景,才能發揮值對象的最大作用。
6 實體 V.S 值對象
主要差別如下:
- 實體有唯一性,值對象沒有。比如使用者具有唯一性,一旦某使用者被系統管理,它就被賦予了在事件、流程和操作中被唯一識别的能力
- 實體着重唯一性和延續性,不在意屬性的變化,屬性全變了,它還是自己;值對象着重描述性,對屬性變化敏感,屬性變了,它就不是自己了
實體和值對象也可能随着系統業務關注點的不同而更換位置。比如,如果另一個限界上下文更關注位址,而不關注與這個位址産生聯系的人員,那就把位址設計成實體,人員設計成值對象
比如多人的機關位址是一樣的,怎麼處理:
許多人可能屬同一位址
許多位址也可能屬同一人
是以人和位址既可分别作為實體而把對方作為值對象,也可共同作為實體描述業務,這正是業務設計的意義,而不是非黑即白。
DDD提倡從領域模型設計出發,而非先設計資料模型。
傳統資料模型設計通常一個表對應一個實體,一個主表關聯多個從表,當實體表太多,就很容易陷入複雜DB設計,領域模型就很容易被資料模型綁架。
在領域模型中人員是實體,位址是值對象,位址值對象被人員實體引用。
設計資料模型時
位址值對象可作為一個屬性集整體嵌入人員實體
也可以序列化大對象的形式加入人員的位址屬性
同樣一個對象在不同場景,可能設計不同:
位址會被某一實體引用,隻描述實體,并且其值隻能整體替換,這時就可将位址設計為值對象,比如收貨位址
位址會被經常修改,位址作為一個獨立對象存在,這時應設計為實體,比如行政區劃中的位址資訊
參考
實體和值對象:從領域模型的基礎單元看系統設計
《實作領域驅動設計》