<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      領域驅動設計和實踐

      聲明: 本文已經首發于InfoQ中文站,版權所有,原文為《領域驅動設計與實踐》,如需轉載,請務必附帶本聲明,謝謝。

      InfoQ中文站是一個面向中高端技術人員的在線獨立社區,為Java、.NET、Ruby、SOA、敏捷、架構等領域提供及時而有深度的資訊、高端技術大會如QCon 、線下技術交流活動QClub、免費迷你書下載如《架構師》等。?

      引言

      軟件系統面向對象的設計思想可謂歷史悠久,20世紀70年代的Smalltalk可以說是面向對象語言的經典,直到今天我們依然將這門語言視為面向對象語言的基礎。隨著編程語言和技術的發展,各種語言特性層出不窮,面向對象是大部分語言的一個基本特性,像C++、Java、C#這樣的靜態語言,Ruby、Python這樣的動態語言都是面向對象的語言。

      但是面向對象語言并不是銀彈,如果開發人員認為使用面向對象語言寫出來的程度本身就是面向對象的,那就大錯特錯了,實際開發中,大量的業務邏輯堆積在一個巨型類中的例子屢見不鮮,代碼的復用性和擴展性無法得到保證。為了解決這樣的問題,領域驅動設計提出了清晰的分層架構和領域對象的概念,讓面向對象的分析和設計進入了一個新的階段,對企業級軟件開發起到了巨大的推動作用。

      本文主要介紹了領域驅動設計的基本概念、要素、特點,對比了事務腳本和領域模型的特點,最后介紹了我們在軟件開發過程中的領域驅動設計實踐。

      什么是領域驅動設計(DDD)

      2004年著名建模專家Eric Evans發表了他最具影響力的書籍:《Domain-Driven Design –Tackling Complexity in the Heart of Software》(中文譯名:領域驅動設計—軟件核心復雜性應對之道),書中提出了“領域驅動設計(簡稱 DDD)”的概念。

      領域驅動設計事實上是針對OOAD的一個擴展和延伸,DDD基于面向對象分析與設計技術,對技術架構進行了分層規劃,同時對每個類進行了策略和類型的劃分。 

      領域模型是領域驅動的核心。采用DDD的設計思想,業務邏輯不再集中在幾個大型的類上,而是由大量相對小的領域對象(類)組成,這些類具備自己的狀態和行為,每個類是相對完整的獨立體,并與現實領域的業務對象映射。領域模型就是由這樣許多的細粒度的類組成。基于領域驅動的設計,保證了系統的可維護性、擴展性和復用性,在處理復雜業務邏輯方面有著先天的優勢。

      領域驅動設計的特點

      領域驅動的核心應用場景就是解決復雜業務的設計問題,其特點與這一核心主題息息相關:

          1. 分層架構與職責劃分:領域驅動設計很好的遵循了關注點分離的原則,提出了成熟、清晰的分層架構。同時對領域對象進行了明確的策略和職責劃分,讓領域對象和現實世界中的業務形成良好的映射關系,為領域專家與開發人員搭建了溝通的橋梁。
          2. 復用:在領域驅動設計中,領域對象是核心,每個領域對象都是一個相對完整的內聚的業務對象描述,所以可以形成直接的復用。同時設計過程是基于領域對象而不是基于數據庫的Schema,所以整個設計也是可以復用的。
          3. 使用場景:適合具備復雜業務邏輯的軟件系統,對軟件的可維護性和擴展性要求比較高。不適用簡單的增刪改查業務。

      如果不使用DDD?

      面對復雜的業務場景和需求,如果沒有建立和實現領域模型,會導致應用架構出現“胖服務層”和“貧血的領域模型”,在這樣的架構中,Service層開始積聚越來越多的業務邏輯,領域對象則成為只有getter和setter方法的數據載體。這種做法還會導致領域特定業務邏輯和規則散布于多個的Service類中,有些情況下還會出現重復的邏輯。我們曾經見過5000多行的Service類,上百個方法,代碼基本上是不可讀的。

      在大多數情況下,貧血的領域模型沒有成本效益。它們不會給公司帶來超越其它公司的競爭優勢,因為在這種架構里要實現業務需求變更,開發并部署到生產環境中去要花費太長的時間。

      領域驅動設計的分層架構和構成要素

      下面我們簡單介紹一下領域驅動設計的分層架構和構成要素,這部分內容在Eric Evans的書中有非常詳盡的描述,想要詳細了解的,最好去讀原版書籍。

      下面這張圖是該書中著名的分層架構圖,如下:

      分層架構

      整個架構分為四層,其核心就是領域層(Domain),所有的業務邏輯應該在領域層實現,具體描述如下:

      用戶界面/展現層

      負責向用戶展現信息以及解釋用戶命令。

      應用層 

      很薄的一層,用來協調應用的活動。它不

      包含業務邏輯。它不保留業務對象的狀態,

      但它保有應用任務的進度狀態。

      領域層 

      本層包含關于領域的信息。這是業務軟件

      的核心所在。在這里保留業務對象的狀態,

      對業務對象和它們狀態的持久化被委托給

      了基礎設施層。

      基礎設施層 

      本層作為其他層的支撐庫存在。它提供了

      層間的通信,實現對業務對象的持久化,

      包含對用戶界面層的支撐庫等作用。

         

        領域驅動設計除了對系統架構進行了分層描述,還對對象(Object)做了明確的職責和策略劃分:

          1. 實體(Entities):具備唯一ID,能夠被持久化,具備業務邏輯,對應現實世界業務對象。
          2. 值對象(Value objects):不具有唯一ID,由對象的屬性描述,一般為內存中的臨時對象,可以用來傳遞參數或對實體進行補充描述。
          3. 工廠(Factories):主要用來創建實體,目前架構實踐中一般采用IOC容器來實現工廠的功能。
          4. 倉庫(Repositories):用來管理實體的集合,封裝持久化框架。
          5. 服務(Services):為上層建筑提供可操作的接口,負責對領域對象進行調度和封裝,同時可以對外提供各種形式的服務。

      當然,DDD中還提出了聚合和聚合根(Aggregate Root)的概念,不過我們在實踐過程發現聚合根有問題復雜化的傾向,用傳統的聚合、組合等概念去描述領域對象之間的關系更容易理解,所以這里對這個概念就不做介紹了。

      事務腳本和領域模型

      Martin Fowler 2004年所著的企業應用架構模式(Patterns of Enterprise Application Architecture)中的第九章領域邏輯模式(Domain Logic Patterns)專門介紹了事務腳本(Transaction Script)和領域模型(Domain Model),理解這兩種模式對設計和構建企業應用軟件非常有幫助,所以有必要介紹一下。

      事務腳本:

      事務腳本的核心是過程,通過過程的調用來組織業務邏輯,每個過程處理來自表現層的單個請求。大部分業務應用都可以被看成一系列事務,從某種程度上來說,通過事務腳本處理業務,就像執行一條條Sql語句來實現數據庫信息的處理。事務腳本把業務邏輯組織成單個過程,在過程中直接調用數據庫,業務邏輯在服務(Service)層處理。

      事務腳本模式可以簡單的通過UML圖表示成這樣:

      由Action層處理UI層的動作請求,將Request中的數據組裝后傳遞給BusinessService,BS層做簡單的邏輯處理后,調用數據訪問對象進行數據持久化,其中VO充當了數據傳輸對象的作用,一般是貧血的POJO,只具備getter和setter方法,沒有狀態和行為。

      事務腳本模式的特點是簡單容易理解,面向過程設計。對于少量邏輯的業務應用來說,事務腳本模式簡單自然,性能良好,容易理解,而且一個事務的處理不會影響其他事務。不過缺點也很明顯,對于復雜的業務邏輯處理力不從心,難以保持良好的設計,事務之間的冗余代碼不斷增多,通過復制粘貼方式進行復用。可維護性和擴展性變差。

      領域模型:

      領域模型的特點也比較明顯, 屬于面向對象設計,領域模型具備自己的屬性行為狀態,并與現實世界的業務對象相映射。各類具備明確的職責劃分,領域對象元素之間通過聚合和引用等關系配合解決實際業務應用和規則。可復用,可維護,易擴展,可以采用合適的設計模型進行詳細設計。缺點是相對復雜,要求設計人員有良好的抽象能力。

      領域模型對應的就是領域驅動設計中劃分的領域層,這里就不詳細討論了。

      在實際的設計中,我們需要根據具體的需求選擇相應的設計模式。具備復雜業務邏輯的核心業務系統適合使用領域模型,簡單的信息管理系統可以考慮采用事務腳本模式。

      領域驅動設計實踐

      下面主要講一下我們在構建企業級應用開發平臺中對DDD的實踐和擴展。

      本人近年來一直在從事企業級應用開發平臺的相關工作,GAP平臺是我們的一個軟件產品,用來解決企業級軟件開發過程中復用、快速開發和過程規范等問題。設計這樣一個平臺,從底層的框架上就應該能夠支撐復雜業務邏輯的系統構建,所以我們在大的架構設計思路上采用了領域驅動設計的思路,并根據實際采用的技術和要實現的功能對DDD的四層架構進行了細化和實現:  

      整個平臺采用了JavaEE的技術及其相關的開源框架。系統的核心業務邏輯由Domain層處理,其中的業務服務(BusinessService)負責處理某個相對內聚的業務邏輯單元,同時對內對外提供本地或遠程的服務。

      下面是對各層的簡要描述:

          1. View:展示層,由于GAP平臺主要面向B/S架構,展示層主要由web資源文件組成,包括JSP,JS和大量的界面控件,同時還采用了AJAX和Flex等RIA技術,負責向用戶展現豐富的界面信息,并執行用戶的命令。
          2. Control:控制層,負責展示層請求的轉發、調度和基礎驗證,同時自動攔截后臺返回的Runtime異常信息,如果控制層需要與第三方系統交互,可以通過Action做遠程的請求。
          3. Domain:領域層,是系統最為豐富的一層,主要負責處理整個系統的業務邏輯。這一層包括業務服務和領域對象,同時負責系統的事務管理。其中業務服務可以提供本地調用和共享遠程服務的功能。
          4. Persistence:持久化層,主要負責數據持久化,支持O/R Mapping和JDBC。對數據源的訪問提供多種方式。

      另外,我們引入了Spring的IOC容器,系統的控制層、領域層和持久化層元素都有IOC容器統一管理,實現完全的接口分離和解耦。同時在控制、領域和持久化層都可以引用日志服務。

      我們對領域驅動要素的定義上和原有的命名和含義上稍有區別。

      原來的服務(Service),我們定義為業務服務(BusinessService),面向業務服務的架構是GAP平臺的核心設計思想,一個業務服務可以由一個或多個領域模型和數據訪問對象(DAO)組成,去實現一個完整的業務邏輯單元。業務服務主要負責事務處理和維護各個領域對象之間的關系,同時為上層訪問提供本地和遠程服務,服務類型包括Web Service,RMI等。

      領域對象由實體(Entity)和值對象(VO)構成,實體類具備自己的屬性和行為、狀態,可以聚合VO,實體類之間可以有聚合關聯等關系,可以由數據訪問對象(DAO)進行持久化。

      持久化由數據訪問對象(DAO)實現,不處理業務邏輯,主要負責實體類的持久化。提供多種持久化方式(O/R Mapping和JDBC)。

      那么如何在去實現領域驅動設計呢?我們總結了以下四個步驟:

          1. 確定業務服務(Business Service):根據業務需求和功能模塊劃分,確定業務單元,每個Business Service是一個內聚的業務單元,覆蓋相關的領域對象。
          2. 定義領域對象(Entity, VO):根據業務單元的業務邏輯定義領域對象,通過UML方法和設計模式描述領域對象。
          3. 定義領域對象的屬性和關聯關系:確定領域對象的各種屬性和各個領域對象之間的關聯關系。
          4. 為領域對象增加行為:根據業務需求(系統用例和界面原型等)為領域對象增加行為,并定義哪些方法要被業務服務引用。

      案例——網上書店

      為了更好的理解領域驅動設計,我們基于以上設計方法,實現了一套簡單的網上書店系統。

      網上書店系統是采用DDD設計思想構建的一個應用系統示例。通過網上書店系統,可以快速理解領域驅動設計。該系統實現網上書店的常用功能:包括瀏覽書籍、挑選書籍、提交訂單、查看訂單、自動折扣、處理訂單、取消訂單等。未登錄用戶可以瀏覽和挑選書籍;已登錄用戶可以提交和查看自己相關的訂單;管理員可以處理訂單。

      經過業務抽象,即使是這樣一個簡單的業務場景也包含了很多領域對象,例如訂單、賬戶、書籍、購物車、購物項、折扣等,通過分析和設計,我們可以得到這樣的設計圖(為了查看方便,圖中的類隱藏了屬性信息):

      BookStoreAction負責處理展現層的請求,并把請求轉發給業務服務IBookStoreBS,業務服務負責調度上圖中顯示的領域對象,處理該場景的所有業務。

      其中領域對象和現實業務的對應關系為:

        • Account——賬戶
        • Order——訂單
        • Book——書籍
        • Cart——購物車
        • Item——訂單項
        • Discount——折扣

      與事務腳本的編程模式不同,領域驅動設計不是把業務邏輯放在BS(BusinessService)中,而是由具備屬性、行為和狀態的領域對象處理。例如Order類,如果是貧血的POJO,那它內部只有與數據表字段對應的屬性以及getter和setter方法,而在領域驅動設計中,則是一個相對獨立的、能夠處理自身關聯業務的領域對象。在本系統中,我們對Order的描述如下:

      訂單的實現類是gap.template.bookstore.model.Order,類中除了聯系方式、郵寄地址等基本屬性外,還有以下領域相關的行為:

          1. init(...),結算時調用方法,根據當前用戶與購物車中的Items初始化訂單,供用戶修改。
          2. submit(...),提交訂單時調用的方法,保存訂單。
          3. cancel(...),取消訂單,把訂單和相關item的狀態設置為“已取消”,然后委托Dao進行持久化。
          4. dispose(...),處理訂單,首先更新訂單項的狀態,然后委托Dao持久化訂單數據。
          5. reSubmit、setItemsStatus......

      通過以上的描述,我們可以看到,Order類基本上覆蓋了現實世界中訂單這個業務的所有行為和狀態,是相對內聚的,這樣的特性使其復用性大大增加,即使未來開發新的模塊,涉及到訂單業務的,可以直接復用Order類。同時在后期維護中,如果我想了解訂單的業務,直接讀Order的代碼就可以了。

      從上圖中我們還可以清晰的看到各個領域對象之間的關系。Order和Cart都聚合了Item,對應都是1...n,Item聚合了Book,對應關系1...1。Order分別與折扣、賬戶發生關聯和調用等等,整個網上書店的場景就這樣描述出來了。

      另外,不要忘了BS,除了起到基礎設施的作用外(事務管理和服務共享),它還要負責調度和維護領域對象之間的關系。因為總會有些業務邏輯,既不屬于這個領域對象,也不屬于那個,那這部分業務由誰來處理呢?由BS來處理。例如在管理員處理訂單這個場景中,首先需要根據訂單信息獲取賬戶,根據賬戶信息確定折扣率,同時進行余額校驗,如果校驗通過,就會調用訂單對象的dispose方法處理訂單,這個場景會涉及到Order、Account、Discount等對象,這樣的業務邏輯,應該由BS實現。

      IBookStoreDao是數據訪問對象,可以被BS調用,用來持久化對象,也可以被領域對象引用,用來持久化自身。

      通過以上的描述,我們可以看到,整個設計和實現是優雅、清晰的。業務邏輯沒有堆積在BS中,而是分散在BS和各個領域對象中,服務和對象都與現實世界的業務息息相關,無論是對領域專家、開發人員和后期維護人員,都能這種方式中獲得自己需要的內容。

      總結

      我們采用領域驅動設計相對比較早,就我個人的檢驗和實踐而言,DDD對構建企業級應用開發平臺和大型核心業務系統的作用是非常明顯的,無論是在產品的穩定性、擴展性、可維護性、生命周期等方面都有顯著的提升。

      但是,由于這樣那樣的原因(復雜度、工期、開發人員能力限制等等),很多人會不自覺的抵制采用DDD,有時候一個軟件項目重寫了兩次,第二次依然不去做良好的設計。事實上采用了DDD的設計方法,我們的設計階段已經變得非常輕量級和敏捷了,開發人員只要能夠把領域模型之間的關系畫出來并描述說明,并與需求人員達成一致,那么做出來的東西基本上是靠譜的。

      在技術領域,只有主動的嘗試和提升,效果才是最明顯的。很多人問過我,如何開始學習和實踐XXX,其實很簡單,現在就開始吧!

      參考資料

      《 領域驅動設計—軟件核心復雜性應對之道》,Evans Eric著,Addison-Wesley出版社

      《企業應用架構模式》, Martin Fowler著, Addison-Wesley出版社


      補充:在微博上與趙姐夫、招財豬豬的探討:

      ###############################################################################

      招財豬豬:看了您的領域驅動設計和實現,如果說領域模型包含行為方法。那不是要和下層的數據訪問有耦合嗎

      答:Model處理自己的業務,依賴持久化層,領域層和持久化層是依賴關系,而且是依賴接口,談不上耦合。只要接口一致,持久化的實現方式可替換。 DDD的討論很久了,我們用的也比較早,但是面試新員工時發現很多人還是不知道或不甚解,所以就想把這部分內容相對清晰的寫一下...

      老趙:你們怎么處理復雜的Model關系的持久化啊?遇到這種問題我發現基本都要在Model里讓步的,Hibernate這種靈活程度也不足以滿足各種問題。

      答:我們一般是這么劃分的,Model可以負責自身的持久化,復雜Model關系的持久化交給Service層調度。當然,我們還有一套數據字典組件,如果基于數據字典的話,持久化就不用開發人員管理,只寫業務,展現、控制和持久化都由數據字典接管。

      老趙:數據字典是指什么啊?其實數據字典能處理的也只是通用的,規范的,模式化的持久化方式吧。其他的還是交給Service調度是吧?還有有沒有感覺一覺給Service調度就容易變成Transactional Script了啊?

      答: 數據字典負責元數據的管理,同時把元數據比如column等映射到展現層,基本上是column-->field-->label/input/control,然后形成視圖,比如查詢視圖、列表視圖、編輯視圖、工具欄視圖,最后形成模板,再形成實際業務。另外服務層主要負責調度領域對象。過于復雜的模型,以至于O/R Mapping處理不了,那就可能是設計上出問題,要么就要Servcie搞定了

      老趙:我怎么覺的領域模型是經常會復雜到orm處理不了的啊?尤其是假如為了性能反范式地設計數據庫時,比如插入條數據后要修改某個統計項。

      答:那就要具體分析了,如果你說的操作是大批量高并發的,確實分兩次做會損耗性能。所以說領域驅動設計解決的是復雜業務邏輯問題,而不是性能。所以事務腳本模式也是根據場景使用的,不是不用。

      老趙:原來是這樣…還有就是你們的dao有哪些接口,又是怎么使用的呢,比如BS是怎么使用的,實體本身是怎么使用的呢。能用文章的例子比如Order的resubmit進行舉例嗎?

      答:BS接管事務,持有DAO,Order的resubmit( IBookStoreDao dao ){ //邏輯判斷; //設置訂單狀態;//設置購買項狀態; dao.update(this); } 你懂的。

      老趙:喔,明白裊…

      ###############################################################################

      posted @ 2011-08-17 21:06  池建強  閱讀(9386)  評論(17)    收藏  舉報
      主站蜘蛛池模板: 日本精品不卡一二三区| 国产精品自在线拍国产手机版| 中文 在线 日韩 亚洲 欧美| 久久96热在精品国产高清| 国产曰批视频免费观看完| 伊人春色激情综合激情网| 欧美亚洲综合成人a∨在线| 伊人久久大香线蕉av色婷婷色| 依依成人精品视频在线观看| 国产熟女高潮一区二区三区| 国内精品久久人妻无码不卡| 四虎国产精品永久入口| 欧产日产国产精品精品| 国精品无码一区二区三区在线蜜臀| 国产一区精品在线免费看| 色妞www精品免费视频| 四虎女优在线视频免费看| 乐亭县| 精品一日韩美女性夜视频| 国产99青青成人A在线| 国产一区二区不卡在线| 国产首页一区二区不卡| 亚洲国产中文字幕在线视频综合| 国产高颜值极品嫩模视频| 精品免费看国产一区二区| 国产高清视频一区二区乱| 爆乳女仆高潮在线观看| 日本无翼乌邪恶大全彩h| 亚洲伊人成无码综合网| 亚洲精品一区二区三区小| 欧美黑人大战白嫩在线| 亚洲蜜臀av乱码久久| 粉嫩一区二区三区粉嫩视频 | 国产欧美在线手机视频| 班戈县| 午夜精品极品粉嫩国产尤物 | 中国CHINA体内裑精亚洲日本| 五月开心六月丁香综合色啪| 内射极品少妇xxxxxhd| 天天干天天日| 深夜释放自己在线观看|