四虎精品视频-四虎精品成人免费网站-四虎黄色网-四虎国产视频-国产免费91-国产蜜臀97一区二区三区

領域驅(qū)動設計實現(xiàn)之路

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

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

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

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

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

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

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

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

  DDD之戰(zhàn)略設計

  需要指出的是,DDD絕非一套單純的技術工具集,但是我所看到的很多程序員卻的確是這么認為的,并且也是懷揣著這樣的想法來使用DDD的。過于拘泥于技術上的實現(xiàn)將導致DDD-Lite。簡單來講,DDD-Lite將導致劣質(zhì)的領域?qū)ο?,因為我們忽略了DDD戰(zhàn)略建模所帶來的好處。

  DDD的戰(zhàn)略設計主要包括領域/子域、通用語言、限界上下文和架構風格等概念。

  領域和子域(Domain/Subdomain)

  既然是領域驅(qū)動設計,那么我們主要的關注點理所當然應該放在如何設計領域模型上,以及對領域模型的劃分。

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

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

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

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

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

  限界上下文(Bounded Context)

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

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

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

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

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

  架構風格(Architecture)

  DDD并不要求采用特定的架構風格,因為它是對架構中立的。你可以采用傳統(tǒng)的三層式架構,也可以采用REST架構和事件驅(qū)動架構等。但是在《實現(xiàn)領域驅(qū)動設計》中,作者比較推崇事件驅(qū)動架構和六邊形(Hexagonal)架構。

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

  抽象不應該依賴于細節(jié),細節(jié)應該依賴于抽象。

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

  那么,我們的領域模型又如何與端口和適配器進行交互呢?

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

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

圖-1 六邊形架構

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

  應用層雖然很薄,但卻非常重要,因為軟件系統(tǒng)的領域邏輯都是通過它暴露出去的,此時的應用層扮演了系統(tǒng)門面(Facade)的角色。

  DDD之戰(zhàn)術設計

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

  行為飽滿的領域?qū)ο?/strong>

  我們希望領域?qū)ο竽軌驕蚀_地表達出業(yè)務意圖,但是多數(shù)時候,我們所看到的卻是充滿getter和setter的領域?qū)ο螅藭r的領域?qū)ο笠呀?jīng)不是領域?qū)ο罅?,而是Martin 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知識庫領域驅(qū)動設計實現(xiàn)之路,轉(zhuǎn)載需保留來源!

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

主站蜘蛛池模板: 我,喜欢你演员表介绍| 廊桥遗梦 电影| 决胜法庭演员表| 王菲电影| https://www.douyin.com| xiuren秀人网最新地址| 糊涂蛋| 保镖电影大全免费| 工会基层组织选举工作条例| 黄网站在线免费| 适度水解奶粉有哪些| 美女xxx69爽爽免费观妞| 电视剧狂飙演员名单| 饶太郎| va在线观看视频| 补锌之王的食物| 免费播放高清完整版电影| 天津电视台体育频道节目单| 江南好简谱| 嗯~啊~快点死我男男视频| 26uuu电影网| 向着胜利前进演员表| 中国汉字大全20000个| 精品视频| 高钧贤| 曹查理的十部经典电影| 一闪一闪亮晶晶钢琴谱简谱| 2035去台湾六一儿童舞蹈| 爸爸去哪儿第一季是哪一年播出| 国产老阿姨| 石灰和碱的6种配方| 情欲视频| ftv girls| 来5566看av激情电影使劲撸| 老公看你的| 分手男女| 依人在线视频| 巴黎宝贝| 超薄轻舞玉女女裤广场舞| 床上黄色片| 九州电影网|