2011-09-19 69 views
4

我想問關於DDD功能的問題。可以說我們有兩個聚合,每個聚合包含值對象地址。根據埃裏克埃文斯DDD,我們應該隔離彼此的聚合,所以第一個聚合的聚合根不能有一個鏈接到地址。坦率地說,這對我來說似乎沒有意義,所以問題是如何解決這種情況?哪個聚合應該包含Address?DDD聚合和價值對象

謝謝

回答

9

您可以使用相同的值對象。但是,只有在聚合根存在於相同有界上下文中並因此對於兩個聚合具有相同含義時才這樣做。如果聚合存在於不同的有界上下文中,則有2個獨立的並且重複。埃裏克正在試圖與一個有限的背景相關的問題泄漏到另一個問題上。

對於大多數人來說,實體與價值對象的關注歸結爲有重複數據問題的人。我們經過如此訓練,可以用單一規範模型的第三範式進行思考。 DDD克服了必要的複雜性,它通過在需要的地方強制重複並允許曾經被認爲是很重要的概念而帶來了不可避免的複雜性。

希望這有助於

+0

您能舉一個有界和無界的上下文的例子嗎?爲了更好的理解。 – madcyree

+1

如果你有一個有序的上下文和一個客戶有界的上下文,你想擁有獨立的地址。客戶和訂單AR位於不同的環境中。如果您有訂單和運輸信息AR,它們位於相同的上下文中,並且您可以使用相同的地址值對象。 –

+0

謝謝你的解釋:) – madcyree

8

值對象是描述某些特徵或屬性 但不攜帶身份的概念的對象。

由於它沒有概念標識,所以不能'引用'或'有鏈接'。你只能'包含'它。比方說你有一個用戶和用戶有年齡。年齡是一個價值對象。如果約翰25歲,簡也25歲,他們不會「參考」同一個年齡段。喬恩的年齡簡直等於簡氏的年齡。所以如果你的地址確實是一個價值對象,那麼你並沒有違反任何聚合邊界。您的聚合根簡單地擁有相同的地址。即使你在技術上具有對地址的java/c#引用,它並不重要,因爲值對象大多數時間是不可變的。

雖然不知道你在做什麼域名,但很難回答你的問題。但通常地址不一定是一個價值對象。埃裏克埃文斯在他的book中提到郵政服務和傳遞路徑域將把地址視爲一個實體。派出技術人員的電氣公司需要認識到'123 Elm St'的兩個服務電話實際上來自同一個地址,並且只需要派一名技術人員。在這種情況下,地址或'住宅'是一個實體。

2

聚合僅與數據修改有關。不應該允許兩個聚合修改相同的數據。由於Value對象是不可變的,所以它可以防止這種情況發生。因此,兩個或多個聚合共享相同的值對象是完全正確的,因爲它是隻讀數據結構,聚合不關心讀取模型。

Address a = new Address("1111 ABC Ave."); 
person.setAddress(a); 
letter.setAddress(a); 

person.getAddress().change("2222 XYS Ave.") // THIS IS ILLEGAL SINCE Address is a VO (immutable) 

以上不會發生的地址,所以它不是危險的分享,因爲你做的人的地址任何事都對信的效果,所以信仍是保護它自己的不變量。

如果將地址製作成實體,那麼您將無法在兩個實體中使用相同的地址,因爲上述代碼會使信件容易受到人身上的更改影響,並且會破壞邊界,並且它會阻止信件控制它的不變量。

這是聚合根的整個觀點,這太模型化了,限制了副作用。如果您定義了非常明確的修改邊界,代碼將更容易處理,並且可以防止潛在的有害意外影響。


我會再添加一件東西。正如在另一個答案中提到的,您希望不同的有界上下文具有不同的地址類型。原因是你在一個上下文中需要的地址細節不一定與你在另一個地址上需要的細節相同。因此,通過使用兩種地址類型(每種情景一種),可以將一種需求與另一種需求分開。

說航運您需要:

Address 
{ 
    Number; 
    Unit; 
    Street; 
    State; 
    Country; 
    PostalCode; 
} 

但對於位置,你需要:

Address 
{ 
    Number; 
    Unit; 
    Latitude; 
    Longitude; 
} 

DDD會說,叫他們兩個地址,但它們綁定到不同的情境。因此,儘管在語言中他們都被稱爲地址,但他們的具體數據和行爲可能會因您所談論的環境而有所不同。你絕對不應該做的是創建一種MonsterAddres,它將包含域中所有上下文的所有可能的數據和行爲,並且這是所有上下文中使用的地址類型。請注意,我們正在討論應用程序中的模型,可以將所有地址數據存儲在怪物地址表中,但是在爲應用程序建模時,應該將其分隔爲映射到您的域的邏輯有界上下文以及它所使用的無處不在的語言。