中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

領域驅動設計 ——一種將概念模型化的方式

發布時間:2020-07-17 11:30:28 來源:網絡 閱讀:995 作者:谷風_ 欄目:開發技術

原文發布于:http://www.gufeng.tech/  谷風的個人主頁

1.引子

      2004年Eric Evans 發表了一本書:《Domain-Driven Design: Tackling Complexity in the Heart of Software》(中文名:《領域驅動設計:軟件核心復雜性應對之道》),在這本書中作者提出了領域驅動設計(DDD)的概念,到現在已經10多年的時間了。

1.1 面向對象與面向對象語言

      面向對象思想已經存在相當長的歷史了(相對于軟件的歷史),我而們使用的語言,很多也都是面向對象的,但是我們使用面向對象的語言就一定能寫出來面向對象的程序嗎?顯然是不可能的。業務邏輯代碼的堆積、缺乏良好設計的系統或模塊亦或是功能,這樣是不能保證代碼的復用性、擴展性的。

1.2  領域模型

      領域驅動設計的出現,就是為了解決這一問題的。領域驅動設計是以建立正確的領域模型為核心,以構建清晰的分層架構基礎,從而使面向對象的開發進入到了一個新的階段。

      領域驅動設計的前提是有一種能夠在領域專家(業務專家)、設計人員、開發人員(為什么會有開發人員,我們會在后面介紹原因)三類參與者通用的溝通語言,在三類參與者的不斷交流、溝通中發現領域概念(業務概念),再將概念固化成模型,最后由領域模型驅動設計并實現。

      說到這里,看上去領域模型并沒有什么特別的地方,與我們日常分析的方式沒什么大的區別,我們首先來簡單介紹寫領域模型的兩個特點:

      1)業務邏輯集中在領域對象(類)上;

      2)每個領域對象是完整和獨立的,并具有自己的屬性和行為。

      在接下來的內容中,我們一起來了解下如何實現領域驅動設計以及領域驅動設計的優點。

2.領域驅動設計

      領域驅動設計涵蓋了領域模型、領域語言、架構設計、實現幾部分內容,下面我們逐一了解一下。

2.1 領域模型

      關于什么是領域模型以及領域模型的特點,在前面內容中我們有了整體的了解,接下來我們就領域模型本身進行一下簡單的了解。

2.1.1 抽象模型

      領域模型是某個邊界內的領域的一個抽象,是客觀世界的模型,首先它使有邊界的,清晰的邊界是領域模型抽象是否完整的一個重要衡量指標。在該領域模型內,我們只關心領域內的內容。

      領域模型只是實際業務的一種反映,與具體實現技術無關。可以說領域模型建立的成功與否,直接關系到最終的實現、使用等等。領域模型確保任參與人在任何時間看到的內容都是一樣的,了解了模型,就能知道實現的步驟。

      領域模型對于提高軟件的維護性、復用性以及業務可理解性等方面都有很好的幫助。領域模型貫穿整個分析、設計、開發過程,前面提到的三類參與者使用一種大家都能理解的語言進行溝通,確保所有人對模型的理解是一致的,這樣最終開發出來的結果和最初的設計才能最大程度的吻合。

      要建立一個好的領域模型并不簡單,甚至可能是一路坎坷,需要領域專家、設計人員、開發人員通力配合、深入交流、共享信息和知識。最后,領域模型要通過文檔或圖形方式展現出來(推薦使用圖形分解整體結構,配以文字說明)。設計足夠好的領域模型,肯定是符合業務需求的,同時也能夠快速響應需求變化。

      與領域模型緊密相關的還有另外一組概念:聚合、聚合根。下面我們來簡單了解下這兩個概念。

      聚合:通過定義對象間的隸屬關系和邊界來實現領域模型的內聚,

      聚合根:聚合內的某個實體,外部調用聚合時,必須從聚合根開始調用,不能繞過。

      關于聚合的一些特點:

      1)每個聚合有一個根和邊界;

      2)內部對象可互相引用,但是外部對象訪問聚合時,必須從聚合根開始;

      3)除根外,其它對象在聚合內保持唯一即可;

      4)聚合內部對象可以保持對其它聚合根的引用;

      5)刪除聚合根時,必須同時刪除其它聚合內對象。

      所有具有獨立含義并且能夠被單獨訪問的內容是聚合。

2.1.2 領域通用語言

      設想一下,領域專家滿口的專業術語,設計人員滿口的設計理論,開發人員滿口的開發語言及算法,這樣的團隊怎么溝通!當然可以引入“翻譯”,但是“翻譯”的結果以及對結果的理解會造成多大程度上的信息丟失,誰也不確定。

      基于以上的原因,迫切需要一種大家都能夠表達出來和理解的語言——這就是領域通用語言。領域通用語言是領域驅動設計的基礎和前提。在三類參與者的各種形式溝通中,都要使用領域通用語言,確保自己的信息能夠被其他人完整、快速的理解。

2.1.3 模型到實現

      假設我們已經擁有了一個非常正確且嚴謹的模型,那么是否能將這個模型直接轉換成代碼嗎?肯定是不行的。所以要求我們在領域建模和設計時,就要考慮最終的代碼實現,將領域模型與實現緊密關聯起來,這就是為什么要有開發人員參與的原因。

      這樣的結構(開發人員參與模型建立、結構設計)有利于盡早發現那些不適合在軟件中實現的模型部分并要求修正,這樣也避免了在最后實現時發現問題、修正設計所帶來的巨大時間損失。同時,因為開發人員參與了模型設計,所以在編碼實現時,都會盡力保護模型不被破壞(因為這是大家共同努力的結果),同時當開發人員發現編碼實現有不滿足模型或者不完善的地方,也會去完善它,進行代碼重構,這樣能夠在很大程度上提升軟件的可靠性,也便于其他人員在接手時能快速了解模型、掌握實現。

2.2 領域驅動設計的架構分層

      我們先來看一張Eric Evans 在他的《Domain-Driven Design: Tackling Complexity in the Heart of Software》一書中提到的分層圖:

領域驅動設計  ——一種將概念模型化的方式

     關于這張圖可能都不陌生,但是每一層在領域驅動設計中的職責是什么?完成什么樣的功能?層與層之間的協作關系是什么樣的?這些問題會在后面一一解釋。

2.2.1 分層

      1)用戶界面

      人機交互部分,沒有特殊內容。

      2)應用

       此應用非彼應用,這里的應用只是很薄的一層,用于給User Interface提供功能接口,并調用Domain完成功能邏輯,看到這里應該有了比較明確的認識了,Application不包括任何業務,只是將根據User Interface的需要提供接口,并完成對一個或者多個Domain的調用。

       本層包含了所有軟件系統要完成的任務,通過本層就能了解整體功能,User Interface僅僅是一種展現方式。

      3)領域

       這一層是整個系統的核心部分,包括了全部的業務邏輯、業務規則等全部業務相關內容。

      4)基礎設施

       這里的基礎設施指的是基礎技術組件,包括消息通信、持久化、緩存等等所有的基礎技術組件。

2.2.2 幾種輔助模式

      1)實體(Entity)

      具有跨越系統的生命周期甚至能超越軟件系統的一系列的延續性和標識符的對象成為實體。簡單說就是具有絕對唯一標識的對象。比如銀行賬戶的ID是唯一的標識,那么一個銀行賬戶就是一個實體。實體擁有自己的屬性,管理自己的內部狀態并對外暴露行為。

      2)值對象(Value Object)

      當我們關心對象的唯一標識而只關心其屬性值的時候,這個對象就是一個值對象。對于值對象,理論上可以被輕易的創建以丟掉。如果是可共享值對象,那應該確保它的值是不可變的。“值對象應該保持盡量的簡單。當其他當事人需要一個值對象時,可以簡單地傳遞值,或者創建一個副本。”

      3)服務(Service)

      是不是所有的領域都能映射成對象呢?顯然是不可能的,那么如何處理不能夠映射成對象的領域呢?這時候就需要服務這個東西了。服務通常對應領域的動作,代表領域中得一些重要行為,而這些行為又不屬于任何一個實體或者值對象。這些行為可以定義為服務對象。

      服務可能存在于領域層、基礎設施層等,所以要區分服務,不要濫用服務。

      服務對象不包含內部狀態,只有行為,所以它提供的主要是行為,作為操作接口存在。我們需要注意的是,不需要對每一個操作創建服務。我們一起來一下服務的幾個特征:

    (1)服務執行的操作涉及一個領域概念,這個領域概念通常不屬于一個實體或者值對象;

    (2)被執行的操作涉及到領域中的其他的對象;

    (3)操作是無狀態的。

      4)模塊(Module)

      當模型巨大,難以整體討論時,需要把這個大得模型拆成幾個關聯的模塊。

      5)聚合&聚合根

      聚合是針對數據變化可以考慮成一個單元的一組相關的對象。聚合使用邊界將內部和外部的對象劃分開來。每個聚合有一個根,是一個實體,并且它是外部可以訪問的唯一的對象。

      關于聚合與聚合根的內容,可參考2.1.1節。

       6)Factory(工廠)

      引入工廠模式,是因為領域模型本身的復雜性決定的,創建領域對象要遠遠比創建pojo對象復雜得多,尤其是聚合會更加復雜。此時引入工廠模式,可以將復雜的實現放在工廠內,外部調用工廠方法即可得到相應領域對象,同時也隱藏了創建邏輯(主要是提供給Application和Infrastructure使用的)。

       7)Repository(倉儲、資源庫)

      倉儲最初的設計目的是用來管理內存中的對象,但我們可以擴展使用,對于需要持久化的領域對象,使用Repository將其持久化到數據庫(或其它持久化存儲)中,再次需要時,可以通過Repository將對象從數據庫中恢復。通常情況下,一個聚合對應一個倉儲。

      那么對于那些不能夠通過單一Repository查詢出來的結果(比如界面中需要展現的數據來源于多個Repository的情況)我們該怎么辦呢?當然可以通過調用多個Repository查詢出結果,但更好的方式是通過CQRS架構來實現,也就是說對于查詢可繞過Domain,直接由Application發起調用另外的架構或者層來實現。

       8)CQRS(Command Query Responsibility Segregation,命令查詢職責分離)

      從字面理解,就是命令和查詢要分離開,那么什么事命令呢?非查詢的操作即命令。結合領域驅動設計,我們可以理解成命令可以通過領域驅動設計完成,查詢則可使用簡單、直接的方式完成(如直接寫SQL)。

      由于是分離的,所以兩部分可以采用相同甚至完全不同的架構來實現,由此引申,是不是數據庫也可以分開設計呢?當然是可以的。

3.結束

      本文中我們粗略的了解了領域驅動設計的一些基本概念、原則和一些所謂的“模式”,在實際使用或者叫“領域驅動設計落地”的過程中,除了一些必須遵守的原則外,我們可以根據自己的業務特點、團隊優勢進行裁剪。

      沒有任何一種語言是具有絕對優勢的,同樣也沒有任何一種設計方法是絕對正確的。找準我們自己的方向,找出適合我們業務特點、團隊特點的方法,并對該方法進行落地裁剪,使之更具生命力、能夠解決我們的實際問題。

      最后,不要迷信、迷戀任何一種或幾種方法、模式,所有的方法都是人根據經驗總結出來,方法、模式可以參考并綜合使用,最終達到擁有自己的方法、自己的模式,這樣才能更好的服務于自己的業務,創造技術體系。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

若尔盖县| 宁陵县| 连南| 宣城市| 南木林县| 巧家县| 永州市| 宁阳县| 友谊县| 定边县| 永胜县| 清水河县| 江达县| 耒阳市| 松桃| 德清县| 广州市| 昭苏县| 乡宁县| 江西省| 福清市| 芜湖县| 招远市| 南溪县| 子长县| 洪雅县| 渝北区| 鄱阳县| 大同县| 土默特左旗| 杭锦旗| 扎赉特旗| 临猗县| 盐边县| 扎兰屯市| 衡水市| 剑河县| 穆棱市| 石阡县| 鄂托克前旗| 渝北区|