初識DDD(Domain Driven Design) (二):軟件架構視角

   本文將從軟件架構角度,介紹DDD的分層架構、組成要素、領域對象生命週期管理等核心概念。

   DDD(Domain Driven Design,領域驅動設計)核心是針對業務層建模的,但是爲了保證業務層的相對獨立性,DDD從最佳實踐經驗出發提出了下面的系統分層:

300px-LayeredArchitecture.png

   我們都知道分層結構的好處。在Martin Fowler的著名的《Patterns of Enterprise Application Architecture》一書中有專門一章講分層(Layering)。上層單向調用下層,下層不應該不知道上層;下層可以通過提供回調(callback,比如Observer模式、模板方法模式等)來注入上層的邏輯,但是下層還是不知道上層。如上面的DDD分層架構圖。

   各層的基本職責如下:    

  1. UI層:與常用的Presentation Tier類似,負責與客戶端交互、展示界面等。上圖也表示了UI層可以調用下面的任一層。

  2. Application層:相當於一個Facade,是薄的一層。定義軟件要做的任務,協調和組織(coordinate)完成用戶請求需要的作業(tasks)並委託(delegate)給Domain層的調用。沒有業務邏輯(rules, knowledge)在裏面。功能有點類似於企業級模式和J2EE模式Front Controller。

  3. Domain層:業務軟件的核心。負責表示業務概念,業務狀況和業務規則。需要注意的是對業務狀態的保存(持久化)的技術細節不屬於這一層(不屬於業務模型),而要委託給Infrastructure層。在該層內部,應該採用Model Driven Design。

  4. Infrastructure層:顧名思義,該層負責提供上面各層需要的通用性服務,如發送消息(Messaging),領域對象的持久化,提供繪製UI所需的Widget,提供各層通信所需框架等。

   有了上面宏觀的分層框架之後,就可以進一步採用DDD的元素對一個初步的領域模型進行細化和實現了。

   我們從基礎的四個元素或說概念說起:Entity,Value Object, Module, Association。Entity用來表示有Identity(俗稱ID)的領域對象。Value Object用來表示沒有Identity的領域值對象。這些對象都帶有屬於領域對象的行爲。Association表示他們之間的聯繫。Module也可以叫Package,用來封裝概念上內聚的一組DDD元素,表達一個具體的領域概念,相當於Java中的package。

   需要注意的是DDD中的Entity與常見的基於SSH框架所做的系統中的Entity的區別。後者往往稱爲貧血的業務對象(amemic domain object),因爲它們只與持久化相關而沒有所屬的業務行爲,只有getter/setter之類的基本方法。相應地那些業務行爲移到了"Service"中。於是Service(或者ServiceImpl)中出現大量過程式(Procedural)的代碼。所以貧血業務對象往往與過程式編程並存。這實際上是違背面向對象理念的。用面向對象的語言(Java,C#等)編寫面向過程的軟件,是很多程序員的通病。DDD所以被稱作“OOP done right”,應該很大程度上取決於它還原了Service和領域對象的“真實面目”。

   在DDD中,Service處理的是cross-cutting的操作,即不屬於某一個領域對象,而屬於某一個Aspect(切面)的操作,有點類似於AOP中的切面。Service可以存在與上面四層中的Application層,或者Domain層,或者Infrastructure層,粒度應該不粗也不細。在Adam Bien 的《Real-World Java EE Patterns - Rethinking best practices》一書中,認爲Domain-Driven和Service-Oriented是矛盾的: "Domain-driven design and service-oriented design are opposite approaches"。另一方面,因爲Service處理的是Cross-cutting的操作,它往往是重構的結果,而不是一開始就建立一堆Service來處理業務。業務的處理應該放在所屬的對象裏面,往往是Entity或者VO裏。這纔是面向對象。在處理複雜多變的業務需求時這種方式的優勢將體現出來。

   上面是模型元素Model Components,下面將一起認識生命週期要素Life Cycle Components:聚合Aggregates,工廠Factory,倉儲Repository。

   聚合Aggregate是數據變化的單位,是一組Entities,VO等組成。聚合有根和邊界。外界訪問聚合只能通過聚合根,只能持有聚合根的引用,不可以持有其他成員的引用。將數據變化用聚合來封裝,可以保證數據一致性約束、不變量等複雜的業務規則得到良好的管理。

   工廠Factory是用來封裝聚合的創建細節。注意這裏的工廠是概念性的,具體實現可以是工廠方法模式,Builder模式等。一般認爲複雜對象的創建才用工廠。簡單對象直接new就可以。

   倉儲Repository封裝對象的存儲和獲取(想起了Spring的XXRepository)。將對象的創建委託給工廠。事務控制應該交給調用Repository的client。

   其他概念如Bounded Context等是與集成有關的,暫不介紹了。

   以上又走馬觀花地review了一遍DDD的重要概念。希望能給讀者一個基本的印象。對DDD來說,也許理解起來很容易(只要對設計模式、企業級架構有一些經驗),但實踐起來很困難,需要不斷摸索。但是早點了解DDD中體現的面向對象的設計思想,對於提高自己的代碼質量和架構質量總是有好處的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章