一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

領(lǐng)域驅(qū)動設(shè)計實(shí)現(xiàn)之路

  2004年,當(dāng)Eric Evans的那本《領(lǐng)域驅(qū)動設(shè)計——軟件核心復(fù)雜性應(yīng)對之道》(后文簡稱《領(lǐng)域驅(qū)動設(shè)計》)出版時,我還在念高中,接觸到領(lǐng)域驅(qū)動設(shè)計(DDD)已經(jīng)是8年后的事情了。那時,我正打算在軟件開發(fā)之路上更進(jìn)一步,經(jīng)同事介紹,我開始接觸DDD。

  我想,多數(shù)有經(jīng)驗(yàn)的程序開發(fā)者都應(yīng)該聽說過DDD,并且嘗試過將其應(yīng)用在自己的項(xiàng)目中。不知你是否遇到過這樣的場景:你創(chuàng)建了一個資源庫(Repository),但一段時間之后發(fā)現(xiàn)這個資源庫和傳統(tǒng)的DAO越來越像了,你開始反思自己的實(shí)現(xiàn)方式是正確的嗎?或者,你創(chuàng)建了一個聚合,然后發(fā)現(xiàn)這個聚合是如此的龐大,它為什么引用了如此多的對象,難道又是我做錯了嗎?

  其實(shí)你并不孤單,我相信多數(shù)同仁都曾遇到過相似的問題。前不久,我一個同事給我展示了他在2007年買的那本已經(jīng)被他韋編三絕過的《領(lǐng)域驅(qū)動設(shè)計》,他告訴我,讀過好幾遍后,他依然不知道如何將DDD付諸實(shí)踐。Eric那本書固然是好,無可否認(rèn),但是我們程序員總希望看到一些實(shí)際的例子能夠切實(shí)將DDD落地以指導(dǎo)我們的日常開發(fā)。

  于是,在Eric的書出版將近10年之后,我們有了《實(shí)現(xiàn)領(lǐng)域驅(qū)動設(shè)計》,作為該書的譯者,我有幸通讀了本書,受益匪淺,得到的結(jié)論是:好的軟件就應(yīng)該是DDD的。

  就像在微電子領(lǐng)域有知識產(chǎn)權(quán)核(Intellectual Property)一樣,DDD將一個軟件系統(tǒng)的核心業(yè)務(wù)功能集中在一個核心域里面,其中包含了實(shí)體、值對象、領(lǐng)域服務(wù)、資源庫和聚合等概念。在此基礎(chǔ)上,DDD提出了一套完整的支撐這樣的核心領(lǐng)域的基礎(chǔ)設(shè)施。此時,DDD已經(jīng)不再是“面向?qū)ο筮M(jìn)階”那么簡單了,而是演變成了一個系統(tǒng)工程。

  所謂領(lǐng)域,即是一個組織的業(yè)務(wù)開展方式,業(yè)務(wù)價值便體現(xiàn)在其中。長久以來,我們程序員都是很好的技術(shù)型思考者,我們總是擅長從技術(shù)的角度來解決項(xiàng)目問題。但是,一個軟件系統(tǒng)是否真正可用是通過它所提供的業(yè)務(wù)價值體現(xiàn)出來的。因此,與其每天鉆在那些永遠(yuǎn)也學(xué)不完的技術(shù)中,何不將我們的關(guān)注點(diǎn)向軟件系統(tǒng)所提供的業(yè)務(wù)價值方向思考思考,這也正是DDD所試圖解決的問題。

  在DDD中,代碼就是設(shè)計本身,你不再需要那些繁文縟節(jié)的并且永遠(yuǎn)也無法得到實(shí)時更新的設(shè)計文檔。編碼者與領(lǐng)域?qū)<以僖膊恍枰g才能理解對方所表達(dá)的意思。

  DDD有戰(zhàn)略設(shè)計和戰(zhàn)術(shù)設(shè)計之分。戰(zhàn)略設(shè)計主要從高層“俯視”我們的軟件系統(tǒng),幫助我們精準(zhǔn)地劃分領(lǐng)域以及處理各個領(lǐng)域之間的關(guān)系;而戰(zhàn)術(shù)設(shè)計則從技術(shù)實(shí)現(xiàn)的層面教會我們?nèi)绾尉唧w地實(shí)施DDD。

  DDD之戰(zhàn)略設(shè)計

  需要指出的是,DDD絕非一套單純的技術(shù)工具集,但是我所看到的很多程序員卻的確是這么認(rèn)為的,并且也是懷揣著這樣的想法來使用DDD的。過于拘泥于技術(shù)上的實(shí)現(xiàn)將導(dǎo)致DDD-Lite。簡單來講,DDD-Lite將導(dǎo)致劣質(zhì)的領(lǐng)域?qū)ο螅驗(yàn)槲覀兒雎粤薉DD戰(zhàn)略建模所帶來的好處。

  DDD的戰(zhàn)略設(shè)計主要包括領(lǐng)域/子域、通用語言、限界上下文和架構(gòu)風(fēng)格等概念。

  領(lǐng)域和子域(Domain/Subdomain)

  既然是領(lǐng)域驅(qū)動設(shè)計,那么我們主要的關(guān)注點(diǎn)理所當(dāng)然應(yīng)該放在如何設(shè)計領(lǐng)域模型上,以及對領(lǐng)域模型的劃分。

  領(lǐng)域并不是多么高深的概念,比如,一個保險公司的領(lǐng)域中包含了保險單、理賠和再保險等概念;一個電商網(wǎng)站的領(lǐng)域包含了產(chǎn)品名錄、訂單、發(fā)票、庫存和物流的概念。這里,我主要講講對領(lǐng)域的劃分,即將一個大的領(lǐng)域劃分成若干個子域。

  在日常開發(fā)中,我們通常會將一個大型的軟件系統(tǒng)拆分成若干個子系統(tǒng)。這種

  劃分有可能是基于架構(gòu)方面的考慮,也有可能是基于基礎(chǔ)設(shè)施的。但是在DDD中,我們對系統(tǒng)的劃分是基于領(lǐng)域的,也即是基于業(yè)務(wù)的。

  于是,問題也來了:首先,哪些概念應(yīng)該建模在哪些子系統(tǒng)里面?我們可能會發(fā)現(xiàn)一個領(lǐng)域概念建模在子系統(tǒng)A中是可以的,而建模在子系統(tǒng)B中似乎也合乎情理。第二個問題是,各個子系統(tǒng)之間的應(yīng)該如何集成?有人可能會說,這不簡單得就像客戶端調(diào)用服務(wù)端那么簡單嗎?問題在于,兩個系統(tǒng)之間的集成涉及到基礎(chǔ)設(shè)施和不同領(lǐng)域概念在兩個系統(tǒng)之間的翻譯,稍不注意,這些概念就會對我們精心創(chuàng)建好的領(lǐng)域模型造成污染。

  如何解決?答案是:限界上下文和上下文映射圖。

  限界上下文(Bounded Context)

  在一個領(lǐng)域/子域中,我們會創(chuàng)建一個概念上的領(lǐng)域邊界,在這個邊界中,任何領(lǐng)域?qū)ο蠖贾槐硎咎囟ㄓ谠撨吔鐑?nèi)部的確切含義。這樣邊界便稱為限界上下文。限界上下文和領(lǐng)域具有一對一的關(guān)系。

  舉個例子,同樣是一本書,在出版階段和出售階段所表達(dá)的概念是不同的,出版階段我們主要關(guān)注的是出版日期,字?jǐn)?shù),出版社和印刷廠等概念,而在出售階段我們則主要關(guān)心價格,物流和發(fā)票等概念。我們應(yīng)該怎么辦呢,將所有這些概念放在單個Book對象中嗎?這不是DDD的做法,DDD有限界上下文將這兩個不同的概念區(qū)分開來。

  從物理上講,一個限界上下文最終可以是一個DLL(.NET)文件或者JAR(Java)文件,甚至可以是一個命名空間(比如Java的package)中的所有對象。但是,技術(shù)本身并不應(yīng)該用來界分限界上下文。

  將一個限界上下文中的所有概念,包括名詞、動詞和形容詞全部集中在一起,我們便為該限界上下文創(chuàng)建了一套通用語言。通用語言是一個團(tuán)隊(duì)所有成員交流時所使用的語言,業(yè)務(wù)分析人員、編碼人員和測試人員都應(yīng)該直接通過通用語言進(jìn)行交流。

  對于上文中提到的各個子域之間的集成問題,其實(shí)也是限界上下文之間的集成問題。在集成時,我們主要關(guān)心的是領(lǐng)域模型和集成手段之間的關(guān)系。比如需要與一個REST資源集成,你需要提供基礎(chǔ)設(shè)施(比如Spring 中的RestTemplate),但是這些設(shè)施并不是你核心領(lǐng)域模型的一部分,你應(yīng)該怎么辦呢?答案是防腐層,該層負(fù)責(zé)與外部服務(wù)提供方打交道,還負(fù)責(zé)將外部概念翻譯成自己的核心領(lǐng)域能夠理解的概念。當(dāng)然,防腐層只是限界上下文之間眾多集成方式的一種,另外還有共享內(nèi)核、開放主機(jī)服務(wù)等,具體細(xì)節(jié)請參考《實(shí)現(xiàn)領(lǐng)域驅(qū)動設(shè)計》原書。限界上下文之間的集成關(guān)系也可以理解為是領(lǐng)域概念在不同上下文之間的映射關(guān)系,因此,限界上下文之間的集成也稱為上下文映射圖。

  架構(gòu)風(fēng)格(Architecture)

  DDD并不要求采用特定的架構(gòu)風(fēng)格,因?yàn)樗菍軜?gòu)中立的。你可以采用傳統(tǒng)的三層式架構(gòu),也可以采用REST架構(gòu)和事件驅(qū)動架構(gòu)等。但是在《實(shí)現(xiàn)領(lǐng)域驅(qū)動設(shè)計》中,作者比較推崇事件驅(qū)動架構(gòu)和六邊形(Hexagonal)架構(gòu)。

  當(dāng)下,面向接口編程和依賴注入原則已經(jīng)在顛覆著傳統(tǒng)的分層架構(gòu),如果再進(jìn)一步,我們便得到了六邊形架構(gòu),也稱為端口和適配器(Ports and Adapters)。在六邊形架構(gòu)中,已經(jīng)不存在分層的概念,所有組件都是平等的。這主要得益于軟件抽象的好處,即各個組件的之間的交互完全通過接口完成,而不是具體的實(shí)現(xiàn)細(xì)節(jié)。正如Robert C. Martin所說:

  抽象不應(yīng)該依賴于細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴于抽象。

  采用六邊形架構(gòu)的系統(tǒng)中存在著很多端口和適配器的組合。端口表示的是一個軟件系統(tǒng)的輸入和輸出,而適配器則是對每一個端口的訪問方式。比如,在一個Web應(yīng)用程序中,HTTP協(xié)議可以作為一個端口,它向用戶提供HTML頁面并且接受用戶的表單提交;而Servlet(對于Java而言)或者Spring中的Controller則是相對應(yīng)于HTTP協(xié)議的適配器。再比如,要對數(shù)據(jù)進(jìn)行持久化,此時的數(shù)據(jù)庫系統(tǒng)則可看成是一個端口,而訪問數(shù)據(jù)庫的Driver則是相應(yīng)于數(shù)據(jù)庫的適配器。如果要為系統(tǒng)增加新的訪問方式,你只需要為該訪問方式添加一個相應(yīng)的端口和適配器即可。

  那么,我們的領(lǐng)域模型又如何與端口和適配器進(jìn)行交互呢?

  上文已經(jīng)提到,軟件系統(tǒng)的真正價值在于提供業(yè)務(wù)功能,我們會將所有的業(yè)務(wù)功能分解為若干個業(yè)務(wù)用例,每一次業(yè)務(wù)用例都表示對軟件系統(tǒng)的一次原子操作。所以首先,軟件系統(tǒng)中應(yīng)該存在這樣的組件,他們的作用即以業(yè)務(wù)用例為單位向外界暴露該系統(tǒng)的業(yè)務(wù)功能。在DDD中,這樣的組件稱為應(yīng)用層(Application Layer)。

  在有了應(yīng)用層之后,軟件系統(tǒng)和外界的交互便變成了適配器和應(yīng)用層之間的交互,如圖-1所示。

圖-1 六邊形架構(gòu)

  從圖-1中可以看出,領(lǐng)域模型位于應(yīng)用程序的核心部分,外界與領(lǐng)域模型的交互都通過應(yīng)用層完成,應(yīng)用層是領(lǐng)域模型的直接客戶。然而,應(yīng)用層中不應(yīng)該包含有業(yè)務(wù)邏輯,否則就造成了領(lǐng)域邏輯的泄漏,而應(yīng)該是很薄的一層,主要起到協(xié)調(diào)的作用,它所做的只是將業(yè)務(wù)操作代理給我們的領(lǐng)域模型。同時,如果我們的業(yè)務(wù)操作有事務(wù)需求,那么對于事務(wù)的管理應(yīng)該放在應(yīng)用層上,因?yàn)槭聞?wù)也是以業(yè)務(wù)用例為單位的。

  應(yīng)用層雖然很薄,但卻非常重要,因?yàn)檐浖到y(tǒng)的領(lǐng)域邏輯都是通過它暴露出去的,此時的應(yīng)用層扮演了系統(tǒng)門面(Facade)的角色。

  DDD之戰(zhàn)術(shù)設(shè)計

  戰(zhàn)略設(shè)計為我們提供一種高層視野來審視我們的軟件系統(tǒng),而戰(zhàn)術(shù)設(shè)計則將戰(zhàn)略設(shè)計進(jìn)行具體化和細(xì)節(jié)化,它主要關(guān)注的是技術(shù)層面的實(shí)施,也是對我們程序員來得最實(shí)在的地方。

  行為飽滿的領(lǐng)域?qū)ο?/strong>

  我們希望領(lǐng)域?qū)ο竽軌驕?zhǔn)確地表達(dá)出業(yè)務(wù)意圖,但是多數(shù)時候,我們所看到的卻是充滿getter和setter的領(lǐng)域?qū)ο螅藭r的領(lǐng)域?qū)ο笠呀?jīng)不是領(lǐng)域?qū)ο罅耍荕artin Fowler所稱之為的貧血對象

  放到Java世界中,多年以來,Java Bean規(guī)范都引誘著程序員們以“自然而然又合乎情理”的方式創(chuàng)建著無數(shù)的貧血對象,而一些框架也規(guī)定對象必須提供getter和setter方法,比如Hibernate的早期版本。那么,貧血對象到底有什么壞處呢?來看一個例子:要修改一個客戶(Customer)的郵箱地址,在使用setter方法時為:

public class Customer {    private String email;    public void setEmail(String email) {        this.email = email;    }} 

it知識庫領(lǐng)域驅(qū)動設(shè)計實(shí)現(xiàn)之路,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 国产对白精品刺激一区二区 | 日韩美女毛片 | 国产91精品一区二区麻豆网站 | 免费国产怡红院在线观看 | 亚洲伊人激情 | 一道精品视频一区二区三区男同 | 国产综合婷婷 | 色视频在线免费看 | 福利片 在线 | 青青国产成人久久91网站站 | 91大西瓜国产线观看免费 | 久久婷婷激情综合色综合也去 | 亚洲精品国产精品乱码不97 | 亚洲激情视频网站 | 国内精自线一二三四2021小说 | 国产三级网站在线观看 | 欧美亚洲图片小说 | 国产全黄三级国产全黄三级书 | 国产亚洲欧美另类久久久 | 久久er99| a爱视频 | 久久综合亚洲伊人色 | 国产一区二区三区久久精品 | 69国产精品视频免费 | 在线观看成人免费视频 | 九九视频网 | 精品欧美一区二区三区四区 | 国产真实伦视频在线视频 | 精品日韩欧美国产一区二区 | 日韩精品一区二区三区中文在线 | 日本色婷婷 | 久久精品免视国产 | 亚洲免费福利 | 麻豆视频观看 | 久久综合九色综合97婷婷女人 | 色多多视频网站 | 狂野欧美性猛交xxxx免费 | 最近中文字幕完先锋资源 | 91手机在线 | 999精品免费视频 | 91久久国产情侣真实对白 |