1. 程式人生 > >領域驅動設計 Domain Driven Design 參考架構詳解

領域驅動設計 Domain Driven Design 參考架構詳解

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

領域驅動設計(Domain Driven Design)參考架構詳解


摘要


本文將介紹領域驅動設計(Domain Driven Design)的官方參考架構,該架構分成了Interfaces、Applications和Domain三層以及包含各類基礎設施的Infrastructure。本文會對架構中一些重要元件和問題進行討論,給出一些分析結論。本文原文連線:

http://blog.csdn.net/bluishglc/article/details/6681253 轉載請註明出處!


目錄


1.      架構概述
2.      架構詳解
        2.1.       Interfaces-介面層
                2.1.1.        DTO
                2.1.2.        Assembler
                2.1.3.        Facade
        2.2.       Application-應用層
        2.3.       Domain-領域層
        2.4.       Infrastructure-基礎設施層
3.      關於架構的一些討論
        3.1.       架構並不能保證領域驅動設計的貫徹與執行
        3.2.       Fa?ade是否是必須的?


1.      架構概述


領域驅動設計(Domain Driven Design)有一個官方的sample工程,名為DDDSample,官網:http://dddsample.sourceforge.net/,該工程給出了一種實踐領域驅動設計的參考架構,本文將對此該架構進行簡單介紹,並就一些重要問題進行討論。


該架構分成了Interfaces、Applications和Domain三層以及包含各類基礎設施的Infrastructure。下圖簡略描述了它們之間的關係:



圖1:領域驅動設計風格的架構草圖(來自於DDDSample官網)


下圖是詳細架構:



圖2:領域驅動設計參考架構


作為參照,下圖展示了傳統TransactionScript風格的架構,可以看出,兩者的差異並不是太大(對於Façade來說,它是一種可選設施,如果系統架構中省略Façade,則DTO與領域物件的互換工作可在service中進行),這也從則面說明推行領域驅動設計的關鍵並不在架構上,而在於整個團隊在分析、設計和開發上沒有自始至終地以領域模型為核心開展工作,以面向物件的思想進行設計和程式設計。


Transaction Script風格的架構具有明顯的“資料”與“操作”分離的特徵,其和領域驅動設計風格的架構在兩個類元件上有質的區別,一個是領域物件,一個是Service。領域驅動設計的架構核心目標是要建立一個富領域模型,其典型特徵是它的領域物件具有豐富的業務方法用以處理業務邏輯,而Transaction Script風格的領域物件則僅僅是資料的載體,沒有業務方法,這種領域也被稱作“貧血的領域物件”(Anemic Domain Objects)。在Service方面,領域驅動設計的架構裡Service是非常“薄“的一層,其並不負責處理業務邏輯,而在TransactionScript風格的架構裡,Service是處理業務邏輯的主要場所,因而往往非常厚重。



圖3:資料與操作分離的Transaction Script風格的架構


2.      架構詳解



2.1.    Interfaces-介面層


領域驅動設計對Interfaces的定位是:


Thislayer holds everything that interacts with other systems, such as web services,RMI interfaces or web applications, and batch processing frontends. It handlesinterpretation, validation and translation of incoming data. It also handlesserialization of outgoing data, such as HTML or XML across HTTP to web browsersor web service clients, or DTO classes and distributed facade interfaces forremote Java clients.


該層包含與其他系統進行互動的介面與通訊設施,在多數應用裡,該層可能提供包括Web Services、RMI或Rest等在內的一種或多種通訊介面。該層主要由Façade、DTO和Assembler三類元件構成,三類元件均是典型的J2EE模式,以下是對三類元件的具體介紹:



2.1.1.   DTO



DTO- DataTransfer Object(資料傳輸物件),也常被稱作VO-Value Object(值物件)。基於面向物件技術設計的領域物件(即通常所說的“實體”)都是細粒度的,將細粒度的領域物件直接傳遞到遠端呼叫端需要進行多次網路通訊,DTO在設計之初的主要考量是以粗粒度的資料結構減少網路通訊並簡化呼叫介面。以下羅列了DTO的多項作用:


  •         Reduces network traffic
  •         Simplifies remote object and remote interface
  •         Transfers more data in fewer remote calls
  •         Reduces code duplication
  •         Introduces stale transfer objects
  •         Increases complexity due to synchronization and version control



圖4.DTO應用時序圖(基於《Core J2EE Patterns》插圖進行了修改)


值得一提的是,DTO對實現一個獨立封閉的領域模型具有積極的作用,特別是當系統使用了某些具有自動髒資料檢查(automatic dirty checking)機制的ORM框架時,DTO的優勢就更加明顯,否則就會存在領域物件在模型層以外被意外修改並自動持久化到資料庫中的風險或者是像Hibernate那樣的框架因未開啟OpenSessionInView (注:開啟OpenSessionInView有副作用,一般認為OpenSessionInView不是一種好的實踐)而導致Lazy Loading出現問題。


關於DTO具體的設計用意和應用場景可參考如下資源:

1.《Core J2EE™ Patterns: Best Practices and Design Strategies, SecondEdition》

2.《Patterns of Enterprise ApplicationArchitecture》


2.1.2.   Assembler



在引入DTO後,DTO與領域物件之間的相互轉換工作多由Assembler承擔,因此Assembler幾乎總是同DTO一起出現。也有一些系統使用反射機制自動實現DTO與領域物件之間的相互轉換,Appache的Commons BeanUtils就提供了類似的功能。應該說這兩種實現各有利弊,使用Assembler進行物件資料交換更為安全與可控,並且接受編譯期檢查,但是程式碼量明顯偏多。使用反射機制自動進行象資料交換雖然程式碼量很少,但卻是非常脆弱的,一旦物件屬性名發生了變化,資料互動就會失敗,並且很難追蹤發現。總體來說,Assembler更為直白和穩妥。



圖5.Assebler應用類圖(基於《Core J2EE Patterns》插圖進行了修改)


關於Assembler具體的設計用意和應用場景可參考如下資源:

1.《Core J2EE™ Patterns: Best Practices and Design Strategies, SecondEdition》

2.《Patterns of Enterprise ApplicationArchitecture》


2.1.3.   Facade



作為一種設計模式同時也是Interfaces層內的一類元件,Façade的用意在於為遠端客戶端提供粗粒度的呼叫介面。Façade本身不處理任何的業務邏輯,它的主要工作就是將一個使用者請求委派給一個或多個Service進行處理,同時藉助Assembler將Service傳入或傳出的領域物件轉化為DTO進行傳輸。以下羅列了Façade的多項作用:


  • Introduces a layer that provides services to remote clients
  • Exposes a uniform coarse-grained interface
  • Reduces coupling between the tiers
  • Promotes layering, increases flexibility and maintainability
  • Reduces complexity
  • Improves performance, reduces fine-grained remote methods
  • Centralizes security management
  • Centralizes transaction control
  • Exposes fewer remote interfaces to clients


實踐Façade的過程中最難把握的問題就是Façade的粒度問題。傳統的Service均以實體為單位進行組織,而Façade應該具有更粗粒度的組織依據,較為合適的粒度依據有:一個高度內聚的模組一個Façade,或者是一個“聚合”(特指領域驅動設計中的聚合)一個Façade.



圖6.Façade應用類圖(基於《Core J2EE Patterns》插圖進行了修改)



圖7.Façade應用時序圖(基於《Core J2EE Patterns》插圖進行了修改)


關於Assembler具體的設計用意和應用場景可參考如下資源:

1.《Core J2EE™ Patterns: Best Practices and Design Strategies, SecondEdition》

2.《Patterns of Enterprise ApplicationArchitecture》

3.《Design Patterns: Elementsof Reusable Object-Oriented Software》


2.2.    Application-應用層


領域驅動設計對Application的定位是:


Theapplication layer is responsible for driving the workflow of the application,matching the use cases at hand. These operations are interface-independent andcan be both synchronous or message-driven. This layer is well suited forspanning transactions, high-level logging and security. The application layeris thin in terms of domain logic - it merely coordinates the domain layerobjects to perform the actual work.


Application層中主要元件就是Service,在領域驅動設計的架構裡,Service的組織粒度和介面設計依據與傳統Transaction Script風格的Service是一致的,但是兩者的實現卻有著質的區別。TransactionScript風格的Service是實現業務邏輯的主要場所,因此往往非常厚重。而在領域驅動設計的架構裡,Application是非常“薄”的一層,所有的Service只負責協調並委派業務邏輯給領域物件進行處理,其本身並真正實現業務邏輯,絕大部分的業務邏輯都由領域物件承載和實現了,這是區別系統是Transaction Script架構還是Domain Model架構的重要標誌。


不管是Transaction Script風格還Domain Model風格,Service都會與多種元件進行互動,這些元件包括:其他的Service、領域物件和Repository 或 DAO。


圖8. Service應用時序圖(基於《Core J2EE Patterns》插圖進行了修改)


Service的介面是面向用例設計的,是控制事務、安全的適宜場所。如果Façade的某一方法需要呼叫兩個以上的Service方法,需要注意事務問題。


2.3.    Domain-領域層


領域驅動設計對Domain的定位是:


Thedomain layer is the heart of the software, and this is where the interestingstuff happens. There is one package per aggregate, and to each aggregatebelongs entities, value objects, domain events, a repository interface andsometimes factories.


Thecore of the business logic belongs in here. The structure and naming ofaggregates, classes and methods in the domain layer should follow theubiquitous language, and you should be able to explain to a domain expert howthis part of the software works by drawing a few simple diagrams and using theactual class and method names of the source code.


Domain層是整個系統的核心層,該層維護一個使用面向物件技術實現的領域模型,幾乎全部的業務邏輯會在該層實現。Domain層包含Entity(實體)、ValueObject(值物件)、Domain Event(領域事件)和Repository(倉儲)等多種重要的領域元件。


2.4.    Infrastructure-基礎設施層



領域驅動設計對Infrastructure的定位是:


Inaddition to the three vertical layers, there is also the infrastructure. As thethe picture shows, it supports all of the three layers in different ways,facilitating communication between the layers. In simple terms, theinfrastructure consists of everything that exists independently of ourapplication: external libraries, database engine, application server, messagingbackend and so on.


Also,we consider code and configuration files that glues the other layers to theinfrastructure as part of the infrastructure layer. Looking for example at thepersistence aspect, the database schema definition, Hibernate configuration andmapping files and implementations of the repository interfaces are part of theinfrastructure layer.


Whileit can be tricky to give a solid definition of what kind of code belongs to theinfrastructure layer for any given situation, it should be possible tocompletely stub out the infrastructure in pure Java unit/scenario tests andstill be able to use the domain layer and possibly the application layer towork out the core business problems.


作為基礎設施層,Infrastructure為Interfaces、Application和Domain三層提供支撐。所有與具體平臺、框架相關的實現會在Infrastructure中提供,避免三層特別是Domain層摻雜進這些實現,從而“汙染”領域模型。Infrastructure中最常見的一類設施是物件持久化的具體實現。


3.      關於架構的一些討論   



3.1.    架構並不能保證領域驅動設計的貫徹與執行



雖然一個合適的架構對於實施領域驅動設計是大有必要的,但只依靠架構是不能保證領域驅動設計的貫徹與執行的。實際上,在這個參考架構上使用Transaction Script的方式進行開法幾乎沒有任何問題,只要開發人員將領域物件變成“貧血”的“資料載體”對待,在service裡實現業務邏輯,那麼該參考架構將成為純粹的TransactionScript方式。當然反過來看,這也體現了這一架構的靈活性。確保領域驅動設計的貫徹與執行需要整個團隊在分析、設計和開發上沒有自始至終地以領域模型為核心開展工作,以面向物件的思想進行設計和程式設計,才能保證實現領域驅動設計。


3.2.    Façade是否是必須的?



儘管在架構中對Façade的定義非常清晰,但在實踐中我發現Façade並不是一個容易拿捏的東西。主要問題在於其與service之間的有太多的重疊與相似之處。我們注意到service是介面是面向一個use case的,因此事務也是追加在service這一層上,於是對於façade而言,99%的情況是,它只是把某個service的某個方法再包裹一下而已,如果把領域物件和DTO的互轉換工作移至service中進行,那麼façade將徹底變成空殼,而關鍵的是:如果service的介面設計是面向和user case的,那麼,毫無疑問,service介面的傳入傳出引數也都應該是DTO,而這一點也在《Core J2EE™ Patterns: Best Practices and Design Strategies, SecondEdition》和《Patterns of Enterprise ApplicationArchitecture》兩書的示例程式碼中完全印證了。那麼,從更為務實角度出發,Façade並非是一種必須的元件。


           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述