貧血模型 和 充血模型

Question: 你認為哪些規則應該封裝在使用案例,而哪些應該封裝在實體 ?

elliot
Feb 6, 2024

前情提要,這是一題公司同仁提出的 QA問答,我希望透過分享我的觀點 以及 記錄的方式,能夠獲得更多的建議,或是在未來回顧時,能重新審視。

首先先讓我們了解 貧血充血 模型各自會碰上什麼事情

貧血 也就是 資料行為 拆開來了,意思是說我們的 邏輯是依附在使用案例上的,這樣會導致 削弱了內聚性,我們的實體或聚合 只是一組資料結構,它沒有辦法表達出 實際上對應的業務內容,傳達 業務知識 的能力相對 薄弱,除此之外這其實是違反物件導向的精神的,它其實是一種更偏向 面對過程 的開發,這也間接的導致你 失去對於資料的控制權,很難確保 資料的正確性和一致性。

充血 也就是 資料行為 聚在一起,有強烈的內聚性能夠表達 對應的業務內容,有較好的傳達業務知識能力,是一種典型的物件導向精神。不過相對的,不擅長應對複雜的業務場景,很容易產生超人類 (賦予太多權限) ,造成依賴關係產生強耦合,使得獨立性和可維護性下降。而 Application Service 層其實只是空空的一層 Facade。

意思是說 不論貧血或充血模型,都會有 其擅長與不擅長 的事情。 而其中如何折衷,如何評估邏輯該歸屬於哪一層級,則可以依據 Eric Evans 的 Domain Driven Design 一書中提到: 應用層,主要是在描述應用程序所要做的工作,並調度豐富的領域模型來完成它。這個層次的任務是描述業務邏輯,或和其它項目的應用層做交互。 這層很薄,不包含任何業務規則或知識,僅用於調度和派發任務給下一層的領域模型,這層沒有業務狀態,但可以爲用戶或程序提供任務狀態。
依據 SRP 原則來看這件事情,一個模組應只對唯一的一個角色負責,因此應用層中的模組應該只負責調度和派發任務,而不應該包含任何業務邏輯或知識。

而最簡單的判別方式有

  1. 一個規則 是否 涉及多個實體(角色)?
  2. 規則是在描述 業務流程(角色) 還是 實體(角色) ?
  3. 規則是否會因為不同場景(角色) 而產生變化?
  4. 規則是否會因為不同的業務需求(角色) 而產生變化?
  5. 你想傳達的是領域知識 還是 使用敘述?

--

--