如何避免寫出爛的業務代碼(2)- 領域對象與領域服務
問題
-
什麼是領域對象
-
什麼是領域服務
-
領域對象的行爲,與領域服務的行爲區別
原因
定義
領域對象: 聚合根,實體,值對象 領域的數據與行爲, 數據和行爲應該與業務產品上的行爲關聯。領域對象通常是有狀態的,理想情況下,我們的領域對象行爲應該和產品業務定義意義映射
-
覺得行爲放在領域服務還是領域對象中區別不大,只是一個放置位置的問題,並不影響到代碼的抽象和複用
-
領域對象中還是隻有屬性,和對象之間的轉換
-
業務邏輯沒有與代碼映射
-
manager(持久化操作)放在領域對象中需要進行一個轉換(ApplicationContext)或者其他方式
-
我們的業務很單薄,放在領域對象中的內容後,領域服務就很單薄了。濫用了領域服務導致了領域對象的貧血
-
領域對象的集合操作
觀點
首先需要對概念明確定義,因爲 DDD 其實是做了一個問題的分治,所以必然會導致在某些情況下,會有單薄這個說法。就像垂直架構中 dao/manager/service 層區分一樣。在初期我們可以明確按照概念來放置代碼,當大家達成共識,深刻理解了這些概念時,沒有其中一層也無所謂了。
舉個例子 eg. 一個 bad case 三個模型:A,B,C, 他們之間存在狀態變更流動。
整理出來的狀態變更圖
AService.cancelBy
AService.changeStatus()
這些方法都在處理狀態,反應不了業務的情況
領域對象:
一般包含以下邏輯
-
領域對象的限制
// 如什麼樣的設計師是不存在的,對於領域外的內容不關心你是不是軟刪,還是硬刪
public void checkDesignerExist() throws BizzException { // 清退的也是不存在的 if (this == null || this.getStatus().equals(DesignerStatusEnum.DELETE)) { throw DdgCoreResponseCode.convertBizzException(DdgCoreResponseCode.DESIGNERNOTEXIST); } }
-
領域行爲與事件 // 如商品對象的刪除,以及事件的 publish(不限於 CRUD) // 抽獎業務中從獎池中選取獎品
-
publicRoulettePrize executeRoulette(finalList<RoulettePrize> prizes,
-
finalInteger dailyFreeRouletteCount,
-
finalint rouletteCountToday,finalUserDTO userDTO)throwsBizzException{
-
finalList<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());
-
finalint totalRate = validPrize.stream().mapToInt(p -> p.getRate()).sum();
-
// 排除無效獎品,計算有效獎品概率之和
-
if(CollectionUtils.isEmpty(validPrize)){
-
throwRouletteResponseCode.convertBizzException(RouletteResponseCode.PRIZE_EMPTY);
-
}
-
return chooseResultPrize(validPrize, totalRate ==0?1: totalRate);
-
}
- 狀態的流轉
不應該做的事
領域對象不應該與其他的模型有交互,如 manager(資源層管理),不應該持久化數據 如何持久化不應該是領域對象關心的。
領域服務
-
構造(複雜的)領域對象 調用防腐層方法,做支撐域和通用域對象的轉換與組合
-
與 dao 層打交道
-
調用其他限界上下文的內容
-
提供領域方法給其他限界上下文 / 應用程序調用
領域服務與領域對象的關係
領域服務通常是領域對象的調用方,是微服務架構下,領域對象對外提供的方式。
AService
1 // 構建領域對象
2 final List<AAggr> aggr = mAManager.listByUserIds(userVal);
3 final AEntity entity = CollectionUtils.isEmpty(aggr) ? null : aggr.get(0)
4 .getA();
5 // 調用領域對象方法
6 entity.checkDesignerExist();
7 entity.checkUpdate();
8
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s?__biz=MzI4NjI3MDc1NA==&mid=2247483800&idx=1&sn=ca57d8b7e44229daecdd3a7103eabca6&chksm=ebde35d5dca9bcc3c828e410dcc6629e3f02b5c46007e2358c7ec905a79115c35faeddbc9dae&scene=21#wechat_redirect