DDD領域驅動設計

參考來源: 使用DDD指導業務設計的一點思考 https://insights.thoughtworks.cn/ddd-business-design/ 后端開發實踐系列——領域驅動設計(DDD)編碼實踐 https://insights.thoughtworks.cn/backend-development-ddd

領域驅動設計指導業務設計

領域驅動設計是什么

領域驅動設計是 Eric Evans 提出的一種軟件設計方法和思想,主要解決業務系統的設計和建模。

理論發展過程

  1. DDD(Domain-Driven Design,領域驅動設計),對應中文版為《領域驅動設計》。

  2. Implement Domain-Driven Design,簡稱IDDD,中文版《實現領域驅動設計》。 3.《領域驅動設計模式、原理與實踐》問世,簡稱PPPDDD。

  3. IDDD的精華版DDDD(Domain-Driven Design Distilled),《領域驅動設計精粹》。

模型和領域模型

模型是能夠表達系統業務邏輯和狀態的對象。 模型,用來反映事物某部分特征的物件,無論是實物還是虛擬的。 領域,指的特定行業或者場景下的業務邏輯。 DDD 中的模型是指反應 IT 系統的業務邏輯和狀態的對象,是從具體業務(領域)中提取出來的,因此又叫做領域模型。

我們可以吧系統復雜的問題分為兩類:

  • 業務復雜度

  • 技術復雜度 技術復雜度,軟件設計中和技術實現相關的問題,例如處理用戶輸入,持久化模型,處理網絡通信等。 業務復雜度,軟件設計中和業務邏輯相關的問題,例如為訂單添加商品,需要計算訂單總價,應用折扣規則等。

識別上下文的邊界是 DDD 中最難得一部分,同時上下文邊界是由業務變化動態變化的,我們把識別出邊界的上下文叫做限界上下文(Bounded Context)。 使用上下文之后,帶來另外一個收獲。模型之間本質上沒有多對多關系,如果有,說明存在一個隱含的成員關系,這個關系沒有被充分的分析出來,對后期的開發會造成非常大的困擾。

我們將那相關性極強的領域模型放到一起考慮,數據的一致性必須解決,同時生命周期也需要保持同步,我們把這個集合叫做聚合

聚合中需要選擇一個代表負責和全局通信,類似于一個部門的接口人,這樣就能確保數據保持一致。我們把這個模型叫做聚合根

相對于非聚合根的模型,我們叫做實體

image

我們把沒有自己生命周期的模型,僅用來呈現多個字段的值的模型和對象,稱作為值對象

image

使用領域模型指導程序設計

指導數據庫設計

使用領域模型建立數據庫的要點:

  • 留意多對多關系,并拆解成一對多關系

  • 值對象和實體往往為一對一關系

  • 使用 ORM 時,聚合根和實體可以配置為級聯刪除和更新

  • 禁止聚合根之間進行關聯

指導 API 設計

RESTful API 已經變成了主流 API 設計方式,當設計好領域對象后,設計 API 的難度大大降低。

使用聚合根作為 URI 的根路徑,使用實體作為子路徑。通過 ID 作為 Path 參數。
image

指導對象設計

領域模型解決業務復雜度的問題,領域模型只應該被用作處理業務邏輯,存儲、業務表現都應該和領域模型無關。 可以把這些 Plain Object 分為三類:

  • DTO,和交互相關或者和后端、第三方服務對接

  • Entity,數據庫表映射

  • Model,領域模型

指導代碼組織

代碼組織,通俗來說就是如何分包。 DDD 特別的抽離出一層叫做 application。這一層是 DDD 的精華,領域模型關心業務邏輯,但是不關心業務場景。

application 用來隔離業務場景,顯得非常重要。
image

領域驅動設計(DDD)編碼實踐

實現業務的3種常見方式

  1. 基于“Service + 貧血模型”的實現 這種方式當前被很多軟件項目所采用,主要的特點是:存在一個貧血的“領域對象”,業務邏輯通過一個Service類實現,然后通過setter方法更新領域對象,最后通過DAO(多數情況下可能使用諸如Hibernate之類的ORM框架)保存到數據庫中。 這種方式依然是一種面向過程的編程范式,違背了最基本的OO原則。另外的問題在于職責劃分模糊不清,使本應該內聚在Order中的業務邏輯泄露到了其他地方(OrderService),導致Order成為一個只是充當數據容器的貧血模型(Anemic Model),而非真正意義上的領域模型。在項目持續演進的過程中,這些業務邏輯會分散在不同的Service類中,最終的結果是代碼變得越來越難以理解進而逐漸喪失擴展能力。

  2. 基于事務腳本的實現 我們會發現領域對象(Order)存在的唯一目的其實是為了讓ORM這樣的工具能夠一次性地持久化,在不使用ORM的情況下,領域對象甚至都沒有必要存在。于是,此時的代碼實現便退化成了事務腳本(Transaction Script),也就是直接將Service類中計算出的結果直接保存到數據庫(或者有時都沒有Service類,直接通過SQL實現業務邏輯)。 在系統足夠簡單的情況下完全可以采用。但是:一方面“簡單”這個度其實并不容易把握;另一方面軟件系統通常會在不斷的演進中加入更多的功能,使得原本簡單的代碼逐漸變得復雜。

  3. 基于領域對象的實現 在這種方式中,核心的業務邏輯被內聚在行為飽滿的領域對象(Order)中,實現Order類如下:

public void changeProductCount(ProductId productId, int count) {
    if (this.status == PAID) {
        throw new OrderCannotBeModifiedException(this.id);
    }
    OrderItem orderItem = retrieveItem(productId);
    orderItem.updateCount(count);
}

然后在Controller或者Service中調用:

@PostMapping("/order/{id}/products")
public void changeProductCount(@PathVariable(name = "id") String id, @RequestBody @Valid ChangeProductCountCommand command) {
    Order order = DAO.byId(orderId(id));
    order.changeProductCount(ProductId.productId(command.getProductId()), command.getCount());
    order.updateTotalPrice();
    DAO.saveOrUpdate(order);
}

可以看到,所有業務(“檢查Order狀態”、“修改Product數量”以及“更新Order總價”)都被包含在了Order對象中,這些正是Order應該具有的職責。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,762評論 2 372

推薦閱讀更多精彩內容