|
引言
本文主要是參考Martion Fowler所著的《企業(yè)應用架構模式》與Eric Evans所著的《領域驅動設計》這兩本泰山之作,加上本人在近年實際的工作過程中開發(fā)SOA系統(tǒng)所認識到的問題所寫的一篇文章,歡迎各位點評。
最后兩節(jié) 細說應用層 、系統(tǒng)總體架構 是本文的重點,著重說明領域驅動設計與SOA之間的關系,對DDD有一定基礎的朋友可以越過前面的幾節(jié),直接查看第七、八節(jié)。
源代碼下載 (數據庫可以在.edmx文件根據模型生成)
一、SOA與DDD的定義
SOA與DDD都是常用的系統(tǒng)架構,但兩者之間所針對的核心是不同的。
SOA(面向服務架構)由Gartner在1996年提出來,它是一種分布式的軟件架構,它可以根據需求通過網絡對松散耦合的粗粒度應用組件進行部署、組合和使用。簡單來說,SOA就是一種大型系統(tǒng)開發(fā)的體系架構,在基于SOA架構的系統(tǒng)中,具體應用程序的功能是由一些松耦合并且具有統(tǒng)一接口的組件(也就是service)組合構建起來的,它是針對多核心多平臺之間的數據交換。
DDD(領域驅動設計)由Eric Evans在2004提出,它的核心內容是“如何將業(yè)務領域概念映射到軟件工程當中”。它推翻了“軟件從數據層開發(fā)設計”的舊習慣,強調領域模型在軟件中發(fā)揮的強大力量,注重如何把企業(yè)內部復雜的業(yè)務流程轉化為軟件。
也許可以認為SOA針對的是大型系統(tǒng)的總體架構,注重如何把系統(tǒng)進行項目分離,隔離開發(fā),最后實現系統(tǒng)合并。而DDD是針對單個項目的開發(fā)管理過程,注重如何利用領域模型把業(yè)務需求轉化為軟件。兩者之間并沒有存在理論上的沖突,能把兩者結合,各展所長,更能發(fā)揮各自的優(yōu)勢。
二、DDD的分層結構
1. 概念
從概念上來說,領域驅動設計架構主要分為基礎設施層、領域層、應用層、表現層4個概念層。
基礎結構層:是為各層提供各項通用技術能力而構建的,它可以為領域層提供像Hibernate、LINQ、ADO.NET等持久化機制,為應用層傳遞消息,為表現層提供插件等等。
領域層:它是系統(tǒng)的核心部分,代表業(yè)務的邏輯概念。它會根據業(yè)務的實際流程定制了業(yè)務信息以及業(yè)務規(guī)則,并按一定的關系制定領域模型。領域模型盡管需要依賴基礎結構層進行保存,但領域模型之間的邏輯關系是跟基礎結構層相隔離的。即使基礎結構層從NHibernate技術轉換成LINQ技術,也不會影響到領域層的結構。領域模型只會依賴實際的業(yè)務邏輯,它只會根據業(yè)務的轉變而靈活變動。
應用層:它的任務是協(xié)調領域層與表現層之間的關系,也可以作為系統(tǒng)與外界溝通的橋梁,在這層里面不會包括任何的業(yè)務邏輯。在SOA面向服務架構,這一層起著重要的作用,在第七節(jié)將詳細說明。
表現層:它是常用的界面開發(fā),可以以頁面(ASP.NET、JSP),窗口(WinForm、WPF、Swing)等形式表現,它的主要職責是負責與用戶進行信息溝通。(注意:在一般的項目開發(fā)中,Web服務會作為與外界通訊的接口放置在表現層中,但在SOA中,Web服務會大多置于應用層中,下面將會作進一步解釋)
2. 開發(fā)實例
在此先舉個常見的訂單管理例子,在下面的章節(jié)里都會以這個實例為參考:
每個用戶在Person表里面都會有一個對應的帳戶,里面記錄了用戶的姓名、地址、電話、積分(Point)等基本信息。
在Order表里記錄的是每次交易的過程,每次商品的送貨費(Freightage)為10元,當商品價格(Price)超過98元可免費送貨,當用戶Person積分(Point)超過2000分可獲7折優(yōu)惠(Favorable),1000~2000分可獲8折,1000分以下可有9折,最后總體價格為為(TotalPrice)。
在最后結單的時候Order表里會產生訂單號碼OrderNumber和下訂日期Delivery,Person表的積分也會加上訂單總價的點數。
最后OrderItem表包含了物品Goods、物品價格Price、購買數量Count等屬性,它主要記錄每次訂單的詳細交易狀況。
上面的業(yè)務邏輯跟淘寶、當當等等大型購物網基本相似。之所以用這樣一個例子作為參考,是想表現一下DDD是如果利用領域模型去適應多變的業(yè)務邏輯關系。
三、把業(yè)務關系轉化為領域模型
1. 概念
模型驅動設計(MODEL-DRIVEN-DESIGN)是DDD里面的核心,它代表的是各個對象之間的關系,把復雜的邏輯關系轉化為模型。
模型主要分為實體(Entity)、值對象(Value Object)與服務(Service)三種。
實體:實體所包含的不單止是一連串的屬性,更重要的是與事件的聯系,在一個生命周期中環(huán)境的變化與事件發(fā)生,將引起實體內部產生變化。好像在實體Order里面,Person的積分(Point)和OrderItem的價格(Price)都會直接影響總體價格(TotalPrice)的大小,而總體價格也會影響到運費Freightage的多少等等。在Order實體的一切,都會受到Person、OrderItem等這些外部因數的影響,這樣的對象被視為實體。在不同的時刻,實體會有不同的狀態(tài),所以在開發(fā)過程中我們需要為實體加上一個“標識符”來區(qū)分對象的身份,它是實體的生命周期里的唯一標志。
值對象:當所用到的對象只有屬性而沒有其他邏輯關系的時候,我們就可以把它視為是值對象。值對象沒有狀態(tài),也不需要有 “標識符”。在多數情況下它可以作為一個屬性存在于一個實體的內部。一般情況下值對象的屬性是不可改變的,當需要更改屬性時,可以把整個對象刪除,然后重新加入一個新對象。
服務:當實體之間存在某些操作,它們并不單一地附屬于某一個實體,而是跟多個實體都有關聯的時候,就可以使用服務來封裝這些操作。值得注意的是服務并非單獨指Web Service, 也并非單單存在于領域層,而是在各個層當中都會存在服務,每一層的服務都有著不同的職能。在基礎結構層服務可能是用于構建身份驗證、電子郵件、錯誤處理等等操作;在領域層,服務更多時候是一種操作,它用于協(xié)調多個實體之間的關系,處理各類的業(yè)務問題;在應用層(特別是在分布式開發(fā)系統(tǒng)內),服務多以Web Service、TCP/IP套接字、MSMQ等等方式實現,服務在此處會作為一個與外界通訊的接口。
- 備注 :這里面也存在一定的爭義,Eric 認為實體所代表的只是多個對象之間的關系,而它們的動作將會由服務來體現出來,這被稱為貧血型模型。但在開發(fā)過程中,越來越多人會把動作加入到實體里面,這被稱為充血型模型。其實不同的問題應該客觀分析,分別對待,在這個例子里面將會以按照 Eric 的定義來開發(fā)服務,在后面的開發(fā)過程中大家也可以從中體現一下服務層所帶來的好處。
2. 實例說明
先以ADO.NET Entity Framework實現模型,Person、Order分別屬于兩個實體,它們都將繼承Root接口,在它們的生命周期內都會生成一個Guid作為標志。此處把OrderItem作為一個值對象置于Order實體內,這意味著OrderItem會通過Order來獲取,外界不能跨越Order直接獲取OrderItem。當然這應該由具體的業(yè)務情況來確定,當外界需要單獨調用OrderItem類的時候,就應該考慮把OrderItem獨立成為一個實體類。
在這里可利用分部類為實體增加Guid屬性,關于分部類于分部方法的詳細介紹可參考C#綜合揭秘——分部類和分部方法
namespace Business.DomainModel
{
public interface Root {
}
public partial class Order:Root
{
private Guid _guid;
public Order()
{
_guid = System.Guid.NewGuid();
}
//為根對象設置唯一的Guid;
public Guid GUID
{
get { return _guid; }
}
}
public partial class Person:Root
{
public Person()
{
_guid = System.Guid.NewGuid();
}
//為根對象設置唯一的Guid;
private Guid _guid;
public Guid GUID
{
get { return _guid; }
}
}
}
it知識庫:結合領域驅動設計的SOA分布式軟件架構,轉載需保留來源!
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。