貧血模型-Martin Fowler 翻譯

劉曉日發表於2011-08-23

作者:Martin Fowler 譯者:劉曉日

貧血模型作為眾多反模式中的一份子,已經有悠久的歷史了,而且現在勢頭正旺。在我與Eric Evans的交談中得知,我們都注意到貧血模型開始越來越流行了。這對於純粹領域模型的忠實粉絲或許不是一件好事兒。

貧血模型一個明顯的特徵是它僅僅是看上去和領域模型一樣,都擁有物件、屬性、物件間通過關係關聯。但是當你觀察模型所持有的業務邏輯時,你會發現,貧血模型中除了一些getter和setter方法,幾乎沒有其他業務邏輯。這種情況事實上是由一些設計規則中(design rules)規定不要把業務邏輯放到“領域模型”中造成的,取而代之的是把所有的業務邏輯都封裝到眾多service中。這些service物件在“領域物件”(領域層)之上形成一個service層,而把“領域物件”當做資料使用。

貧血模型從根本上就違背了物件導向設計將屬性與操作融合的思想。貧血模型就是我們純粹的物件導向忠實者(比如我和Eric)從Smalltalk早期就極力反對的程式導向化設計的風格。更糟糕的是,很多人認為貧血模型就是真正的物件導向,進而也就完全領悟不到物件導向設計的真諦。

純粹的物件導向已經很好了,但是,我知道我需要列出更多的論點去反駁貧血模型。貧血模型一個致命的缺陷就是與領域模型所消耗同樣多的資源,卻沒有得到任何領域模型所具有的優點。這種消耗主要在建立與資料庫的對映上,這樣就單獨劃分出一層專注於O/R對映。當你使用功能強大的物件導向技術時,這樣做是值得的。而這種將業務邏輯統統放到service中是赤裸裸的面向事務程式設計的方式,這樣領域模型所能帶來的優勢消失殆盡。然而就像我在“P of EAA”中所說的那樣,領域模型並不總是“銀彈”。

這裡值得強調一下,將業務行為放到領域模型同使用分層技巧將領域邏輯、持久層和展現層分離是不衝突的。不管你喜歡叫它什麼,領域模型所持有的邏輯(比如驗證、計算、業務規則等)就叫領域邏輯。(有時候你可能會力主在領域物件里加入資料來源或表示邏輯,但這和我說的貧血無關)(注:此句來自豆他爹。超級感謝豆他爹的翻譯,太犀利了,看完我就覺得就是這樣啊,醍醐灌頂的感覺。)

造成物件導向現狀混亂的一個主要因素是許多物件導向專家就建議在領域模型之上增加一個service層。但是這不能作為不把領域邏輯放到領域模型中的依據,事實上service層應該結合領域模型中持有的領域邏輯方法一起使用。

在享譽全球Eric Evans大師的《領域驅動設計》一書中,這樣描述這些層的職責(應用層、領域層翻譯引自《領域驅動設計-軟體核心複雜性應對之道》一書44頁):

應用層(service層):定義軟體要完成的任務,並且只會表達領域概念的物件來解決問題。這一層所負責的工作對業務來說意義重大,也是與其他系統的應用層進行互動的必要渠道。 應用層贏儘量簡單,不包括業務規則或者知識,而只為下一層中的領域物件協調任務,分配工作,使他們互相協作。它沒有反應業務情況的狀態,但是卻可以具有另外一種狀態,為使用者或程式顯示某個任務的進度。

領域層(或模型層):負責表達業務概念,業務狀態資訊以及業務規則。儘管儲存業務狀態的技術細節是有基礎設施層實現的,但是反應業務情況的狀態是有本層控制並且使用的。領域層是業務軟體的核心。

這裡所說的關鍵點是service層很薄(所有業務邏輯都在領域層)。Eric Evans在service層中反覆強調這個觀點:

如今,在實踐DDD過程中最常見的錯誤是,過早的放棄將領域邏輯放到一個合適的領域模型中,從而滑向了過程化程式設計的“深淵”。

如今,不知道為什麼這種反模式可以當道,據我揣測,可能是眾多的開發人員,尤其是有從事資料相關背景的開發人員,根本就沒有使用過純粹的領域模型。有些技術鼓勵使用領域模型,比如J2EE中的實體Bean。這也是我喜歡POJO領域模型的原因。

總之,將越多的領域邏輯放到service中,你就越難體會到領域模型帶來的好處。如果你所有的領域邏輯都在service中,那你得不到任何領域模型帶來的好處。

原文地址:http://martinfowler.com/bliki/AnemicDomainModel.html

宣告,本文為原創翻譯,由於小人才疏學淺,加之第一次翻譯e文,如有不合適的地方,煩請各位指正。

其中有些地方加入自己的理解,如理解錯誤,望見諒。

相關文章