DDD-領域物件與領域服務
問題
- 什麼是領域物件
- 什麼是領域服務
- 領域物件的行為,與領域服務的行為區別
原因
為什麼把這麼小的點拿出來講,最開始在討論中領域物件與領域服務時,覺得行為放在service/entity中區別不大,只是一個放置位置的問題,並不影響到程式碼的抽象和複用,所以沒有實行。但是最近在推動產品進行DDD業務建模,發現這個問題非常重要,關係到程式碼是否清晰表達了業務,這個也是我們進行DDD的初衷。
定義
領域物件:
聚合根,實體,值物件
領域的資料與行為,
資料和行為應該與業務產品上的行為關聯。領域物件通常是有狀態的,理想情況下,我們的領域物件行為應該和產品業務定義意義對映
幾個阻抗
- 覺得行為放在領域服務還是領域物件中區別不大,只是一個放置位置的問題,並不影響到程式碼的抽象和複用
- 領域物件中還是隻有屬性,和物件之間的轉換
- 業務邏輯沒有與程式碼對映
- manager(持久化操作)放在領域物件中需要進行一個轉換(ApplicationContext)或者其他方式
- 我們的業務很單薄,放在領域物件中的內容後,領域服務就很單薄了。濫用了領域服務導致了領域物件的貧血
- 領域物件的集合操作
觀點
首先需要對概念明確定義,因為DDD其實是做了一個問題的分治,所以必然會導致在某些情況下,會有單薄這個說法。就像垂直架構中dao/manager/service層區分一樣。在初期我們可以明確按照概念來放置程式碼,當大家達成共識,深刻理解了這些概念時,沒有其中一層也無所謂了。
舉個例子
eg. 一個bad case
三個模型:A,B,C,他們之間存在狀態變更流動。
整理出來的狀態變更圖
AService.updateXXStatus
AService.cancelBy
AService.changeStatus()
這些方法都在處理狀態,反應不了業務的情況
領域物件:
一般包含以下邏輯
-
領域物件的限制
// 如什麼樣的設計師是不存在的,對於領域外的內容不關心你是不是軟刪,還是硬刪
public void checkDesignerExist() throws BizzException { // 清退的也是不存在的 if (this == null || this.getStatus().equals(DesignerStatusEnum.DELETE)) { throw DdgCoreResponseCode.convertBizzException(DdgCoreResponseCode.DESIGNER_NOT_EXIST); } }
-
領域行為與事件
// 如商品物件的刪除,以及事件的publish(不限於CRUD)
// 抽獎業務中從獎池中選取獎品public RoulettePrize executeRoulette(final List<RoulettePrize> prizes, final Integer dailyFreeRouletteCount, final int rouletteCountToday, final UserDTO userDTO) throws BizzException { final List<RoulettePrize> validPrize = prizes.stream().filter(p -> checkPrizeValid(p)) // 排除掉中獎概率不合法和概率為0的獎品 .filter(p -> ArithUtil.checkIntegerRange(p.getRate(), 0, Integer.MAX_VALUE)) // 校驗中獎次數限制 .filter(p -> checkPrizeLimit(p)) // 校驗vip獎品限制 .filter(p -> checkPrizeVip(p, userDTO)) .filter(p -> checkFreePrize(p,dailyFreeRouletteCount, rouletteCountToday)).collect( Collectors.toList()); final int totalRate = validPrize.stream().mapToInt(p -> p.getRate()).sum(); // 排除無效獎品,計算有效獎品概率之和 if (CollectionUtils.isEmpty(validPrize)) { throw RouletteResponseCode.convertBizzException(RouletteResponseCode.PRIZE_EMPTY); } return chooseResultPrize(validPrize, totalRate == 0 ? 1 : totalRate); }
-
狀態的流轉
不應該做的事
領域物件不應該與其他的模型有互動,如manager(資源層管理),不應該持久化資料
如何持久化不應該是領域物件關心的。
領域服務
-
構造(複雜的)領域物件
呼叫防腐層方法,做支撐域和通用域物件的轉換與組合 -
與dao層打交道
-
呼叫其他限界上下文的內容
-
提供領域方法給其他限界上下文/應用程式呼叫
領域服務與領域物件的關係
領域服務通常是領域物件的呼叫方,是微服務架構下,領域物件對外提供的方式。
AService
// 構建領域物件
final List<AAggr> aggr = mAManager.listByUserIds(userVal);
final AEntity entity = CollectionUtils.isEmpty(aggr) ? null : aggr.get(0)
.getA();
// 呼叫領域物件方法
entity.checkDesignerExist();
entity.checkUpdate();
相關文章
- DDD-領域驅動設計示例
- 領域驅動設計戰術模式--領域服務模式
- 戲說領域驅動設計(廿一)——領域服務
- DDD-領域驅動設計簡談
- Spring GraphQL與Netflix領域圖服務框架整合Spring框架
- 工位出租,場景服務領域升級
- 領域驅動模型DDD(一)——服務拆分策略模型
- 戲說領域驅動設計(十二)——服務
- DDD領域驅動設計:領域事件事件
- 區塊鏈的應用領域——公共服務(三)區塊鏈
- 領域驅動設計,中臺與微服務微服務
- 到底什麼是微服務?其實就是DDD領域服務微服務
- 領域驅動設計戰術模式--領域事件模式事件
- 讀書系列-《解構領域驅動》-領域概念
- 戲說領域驅動設計(廿五)——領域事件事件
- 結合領域事件和微服務的實現領域驅動設計 - Alagarsamy事件微服務
- 內地再向香港開放11個服務領域(轉)
- 領域設計:聚合與聚合根
- 服裝供應鏈領域的佈局與發展
- 微服務領域的軟體架構微服務架構
- redis在微服務領域的貢獻Redis微服務
- 微服務領域驅動設計 - semaphoreci微服務
- 架構師之路 - 業務領域建模架構
- 領域驅動設計戰術模式--值物件模式物件
- 戲說領域驅動設計(二十)——值物件物件
- 淺談領域模型模型
- ABP框架領域層框架
- nodejs應用領域NodeJS
- Linux 應用領域Linux
- 《實現領域驅動設計》筆記——領域、子域和限界上下文筆記
- ABP與DDD領域驅動關係
- DDD劃分領域、子域,核心域,支撐域的目的
- 聚焦再迴圈材料領域,SGS推出GRS/RCS認證服務
- 微服務不是全部,只是特定領域的子集微服務
- 聚焦“加快構建服裝領域新型標準”
- 區塊鏈的應用領域—物聯網和物流領域(二)區塊鏈
- 初識ABP vNext(11):聚合根、倉儲、領域服務、應用服務、Blob儲存
- 核心領域模式 -Nick Tune模式