談一下你對(duì)DDD的理解?我:馬什么梅?
領(lǐng)域模型(domain model)是對(duì)領(lǐng)域內(nèi)的概念類或現(xiàn)實(shí)世界中對(duì)象的可視化表示。領(lǐng)域模型也稱為概念模型、領(lǐng)域?qū)ο竽P秃头治鰧?duì)象模型。
——《UML和模式應(yīng)用》
我們?cè)谌粘i_發(fā)中,經(jīng)常針對(duì)一些功能點(diǎn)爭(zhēng)論“這個(gè)功能不應(yīng)該我改,應(yīng)該是你那邊改”,最終被妥協(xié)改了之后都改不明白為什么這個(gè)功能要在自己這邊改。區(qū)別于傳統(tǒng)的架構(gòu)設(shè)計(jì),領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD)也許在這個(gè)時(shí)候能幫助你做到清晰的劃分。
什么是DDD
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)最初由Eric Evans提出,但是多年以來(lái)一直停留在理念階段,真正能實(shí)現(xiàn)并且落地的項(xiàng)目和公司少之又少,而進(jìn)來(lái)阿里內(nèi)部其實(shí)在大力推行DDD的理念,它主要可以幫助我們解決傳統(tǒng)單體式集中架構(gòu)難以快速響應(yīng)業(yè)務(wù)需求落地的問題,并且針對(duì)中臺(tái)和微服務(wù)盛行的場(chǎng)景做出指導(dǎo)。
DDD為我們提供的是架構(gòu)設(shè)計(jì)的方法論,既面向技術(shù)也面向業(yè)務(wù),從業(yè)務(wù)的角度來(lái)把握設(shè)計(jì)方案。
DDD的作用
統(tǒng)一思想:統(tǒng)一項(xiàng)目各方業(yè)務(wù)、產(chǎn)品、開發(fā)對(duì)問題的認(rèn)知,而不是開發(fā)和產(chǎn)品統(tǒng)一,業(yè)務(wù)又和產(chǎn)品統(tǒng)一從而產(chǎn)生分歧。
明確分工:域模型需要明確定義來(lái)解決方方面面的問題,而針對(duì)這些問題則形成了團(tuán)隊(duì)分鐘的理解。
反映變化:需求是不斷變化的,因此我們的模型也是在不斷的變化的。領(lǐng)域模型則可以真實(shí)的反映這些變化。
邊界分離:領(lǐng)域模型與數(shù)據(jù)模型分離,用領(lǐng)域模型來(lái)界定哪些需求在什么地方實(shí)現(xiàn),保持結(jié)構(gòu)清晰。
DDD的概念
實(shí)體
有唯一標(biāo)志的核心領(lǐng)域?qū)ο?,且這個(gè)標(biāo)志在整個(gè)軟件生命周期中都不會(huì)發(fā)生變化。這個(gè)概念和我們平時(shí)軟件模型中和數(shù)據(jù)庫(kù)打交道的Model實(shí)例比較接近,唯一不同的是DDD中這些實(shí)體會(huì)包含與該實(shí)體相關(guān)的業(yè)務(wù)邏輯,它是操作行為的載體。
值對(duì)象
依附于實(shí)體存在,通過對(duì)象屬性來(lái)識(shí)別的對(duì)象,它將一些相關(guān)的實(shí)體屬性打包在一起處理,形成一個(gè)新的對(duì)象。
舉個(gè)栗子:比如用戶實(shí)體,包含用戶名、密碼、年齡、地址,地址又包含省市區(qū)等屬性,而將省市區(qū)這些屬性打包成一個(gè)屬性集合就是值對(duì)象。
聚合
實(shí)體和值對(duì)象表現(xiàn)的是個(gè)體的能力,而我們的業(yè)務(wù)邏輯往往很復(fù)雜,依賴個(gè)體是無(wú)法完成的,這時(shí)候就需要多個(gè)實(shí)體和值對(duì)象一起協(xié)同工作,而這個(gè)協(xié)同的組織就是聚合。聚合是數(shù)據(jù)修改和持久化的基本單元,同一個(gè)聚合內(nèi)要保證事務(wù)的一致性,所以在設(shè)計(jì)的時(shí)候要保證聚合的設(shè)計(jì)拆分到最小化以保證效率和性能。
聚合根
也叫做根實(shí)體,一個(gè)特殊的實(shí)體,它是聚合的管理者,代表聚合的入口,抓住聚合根可以抓住整個(gè)聚合。
領(lǐng)域服務(wù)
有些領(lǐng)域的操作是一些動(dòng)詞,并不能簡(jiǎn)單的把他們歸類到某個(gè)實(shí)體或者值對(duì)象中。這樣的行為從領(lǐng)域中識(shí)別出來(lái)之后應(yīng)該將它聲明成一個(gè)服務(wù),它的作用僅僅是為領(lǐng)域提供相應(yīng)的功能。
領(lǐng)域事件
在特定的領(lǐng)域由用戶動(dòng)作觸發(fā),表示發(fā)生在過去的事件。比如充值成功、充值失敗的事件。
四種模式
失血模型
模型中只有簡(jiǎn)單的get set方法,是對(duì)一個(gè)實(shí)體最簡(jiǎn)單的封裝,其他所有的業(yè)務(wù)行為由服務(wù)類來(lái)完成。
- @Data
- @ToString
- public class User {
- private Long id;
- private String username;
- private String password;
- private Integer status;
- private Date createdAt;
- private Date updatedAt;
- private Integer isDeleted;
- }
- public class UserService{
- public boolean isActive(User user){
- return user.getStatus().equals(StatusEnum.ACTIVE.getCode());
- }
- }
貧血模型
在失血模型基礎(chǔ)之上聚合了業(yè)務(wù)領(lǐng)域行為,領(lǐng)域?qū)ο蟮臓顟B(tài)變化停留在內(nèi)存層面,不關(guān)心數(shù)據(jù)持久化。
- @Data
- @ToString
- public class User {
- private Long id;
- private String username;
- private String password;
- private Integer status;
- private Date createdAt;
- private Date updatedAt;
- private Integer isDeleted;
- public boolean isActive(User user){
- return user.getStatus().equals(StatusEnum.ACTIVE.getCode());
- }
- public void setUsername(String username){
- return username.trim();
- }
- }
充血模型
在貧血模型基礎(chǔ)上,負(fù)責(zé)數(shù)據(jù)的持久化。
- @Data
- @ToString
- public class User {
- private Long id;
- private String username;
- private String password;
- private Integer status;
- private Date createdAt;
- private Date updatedAt;
- private Integer isDeleted;
- private UserRepository userRepository;
- public boolean isActive(User user){
- return user.getStatus().equals(StatusEnum.ACTIVE.getCode());
- }
- public void setUsername(String username){
- this.username = username.trim();
- userRepository.update(user);
- }
- }
脹血模型
service都不需要,所有的業(yè)務(wù)邏輯、數(shù)據(jù)存儲(chǔ)都放到一個(gè)類中。
對(duì)于DDD來(lái)說,失血和脹血都是不合適的,失血太輕量沒有聚合,脹血那是初學(xué)者才這樣寫代碼。那么充血模型和貧血模型該怎么選擇?充血模型依賴repository接口,與數(shù)據(jù)存儲(chǔ)緊密相關(guān),有破壞程序穩(wěn)定性的風(fēng)險(xiǎn)。
建模方法
用例分析法
用例分析法是領(lǐng)域建模最簡(jiǎn)單可行的方式。大致可以分為獲取用例、收集實(shí)體、添加關(guān)聯(lián)、添加屬性、模型精化幾個(gè)步驟。
- 獲取用例:提取領(lǐng)域規(guī)則描述
- 收集實(shí)體:定位實(shí)體,
- 添加關(guān)聯(lián):兩個(gè)實(shí)體間用動(dòng)詞關(guān)聯(lián)起來(lái)
- 添加屬性:獲取實(shí)體屬性
- 模型精化:可選的步驟,可以用UML的泛華和組合來(lái)表達(dá)模型間的關(guān)系,同時(shí)可以做子領(lǐng)域的劃分
四色建模法
四色建模法源于《Java Modeling In Color With UML》,它是一種模型的分析和設(shè)計(jì)方法,通過把所有模型分為四種類型,幫助模型做到清晰、可追溯。
簡(jiǎn)單來(lái)說,四色關(guān)注的是某個(gè)人的角色在某個(gè)地點(diǎn)的角色用某個(gè)東西的角色做了某件事情。
事件風(fēng)暴法
事件風(fēng)暴法類似頭腦風(fēng)暴,簡(jiǎn)單來(lái)說就是誰(shuí)在何時(shí)基于什么做了什么,產(chǎn)生了什么,影響了什么事情。
架構(gòu)分層
區(qū)別于左圖傳統(tǒng)架構(gòu)的分層,一般DDD分層會(huì)有一些變化。
Application:包含事件注冊(cè)、業(yè)務(wù)邏輯等
Domain:聚合、實(shí)體、值對(duì)象
InfraStructure:基礎(chǔ)設(shè)施封裝、數(shù)據(jù)庫(kù)訪問等
總結(jié)
DDD是一套完善的方法論,他能幫助我們合理的對(duì)系統(tǒng)進(jìn)行架構(gòu)設(shè)計(jì),同時(shí),好的模板應(yīng)該是在不斷的適應(yīng)變化,而DDD也能幫助我們更快速更方便的支撐業(yè)務(wù)的發(fā)展。
本文轉(zhuǎn)載自微信公眾號(hào)「科技繆繆」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系科技繆繆公眾號(hào)。