2

我正在嘗試域驅動設計和事件採購。我打算使用(在C#中開發)NServiceBus,JOliver的EventStore和NES綁定它們。我已經有了一個簡單案例的基礎結構(只有一個具有值對象的聚合根)。DDD:繼承和交易

我正在閱讀埃文斯藍色書籍,我正在嘗試開發一個簡單的領域模型,並從我的工作領域(暖通空調維護公司的ERP和CRM)中抽取實例。

我正在建模一個簡單的子域,即HVAC機器和它們之間的關係。機器有各種類型,例如熔爐,燃燒器,空調,壓縮機,通用組件。每臺機器可以有多臺兒童機器。所有機器類型共享一些常見數據和一些常見行爲。但每種類型都有其他數據和特定行爲,例如,您只能將燃燒器對象添加到爐子中。

我的分析的第一個結果是每臺機器都應該是一個聚合根(從NES中的AggregateBase繼承而來),因爲它必須能夠保存對特定機器的引用(例如插入涉及單個機器的修復記錄,故障記錄等),還可以減少大型機器樹中的併發問題。

我的假設是這樣如下:

public class Machine : AggregateBase 
{ 
    public DateTime InstallationDate { get; private set; } 

    public Guid ManufacturerId { get; private set; } 

    public Guid ModelId { get; private set; } 
} 

public class Furnace : Machine 
{ 
    public List<Burner> burners { get; private set; } 

    // other furnace properties 

    public void AddBurner(Burner burner) 
    { 
     // perform validation 
     this.Apply<BurnerAdded>(x=> x.burnerAdded = burner); 
    } 

    public void Handle(BurnerAdded @event) 
    { 
     this.burners.Add(@event.burnerAdded); 
    } 
} 

public class Burner : Machine 
{ 
    // burner specific properties/methods 
} 

,但是我有些疑惑:

  1. 這是代表我的域名以正確的方式?我讀過類繼承是不鼓勵的,但在我看來,這是一個完美的例子(一個燃燒器是一臺機器,一個爐子也是如此)。我將僅限於一個級別的繼承。

  2. 是否有可能通過Event Sourcing實現類繼承?特別是建議的技術棧(nServiceBus,EventStore,NES)?

  3. 我應該如何執行添加子機(例如爐子的燃燒器)?此操作可分爲兩部分:

    1. 將新的Burner添加到Burner存儲庫。
    2. 添加一個引用到燃燒器的父爐燃燒器列表 但這兩個操作全局修改兩個聚合根,所以操作應該在兩個獨立的命令處理程序/交易中執行......但第二個取決於第一個...這是一些模型錯誤的證據嗎?我可以批量nServicebusMessages在一起執行操作,但我讀了這是不好的...

    如果我讓孩子機器引用父,父母丟失兒童機器列表(其中需要進行驗證),我無法查詢事件採購存儲庫以獲取Guid以外的其他屬性。

預先感謝在討論任何貢獻,

回答

3

#1,我會說不。您示例中的聚合根應該是Furnace(僅)。正如你目前所擁有的那樣,燃燒器應該被模擬爲爐子上的一個集合,但不應該是一個聚合根。除了事實上你的刻錄機現在是一個通過繼承的聚合根(因爲Burner => Machine => AggregateBase),我沒有看到繼承本身就是一個問題。

如果刻錄機只在爐的情況下存在,你也許並不需要一個刻錄機庫 - 你將永遠燃燒器添加到爐。我不清楚創建新的刻錄機本身是否有趣,並且需要自己的事件。這個問題的答案將推動你是否需要這兩個事件或只是「增加」事件。

+0

感謝您的幫助。問題在於燃燒器獨立於爐子存在,它只是一個可以在熔爐之間切換的組件(因此它肯定具有標識),並且可以被其他域對象直接引用(例如服務事件) – Max 2013-02-18 08:49:14

1
  1. 我會避免繼承。相反,請創建單個機器集合並創建本機器將引用的描述符對象。描述符將是一個值對象,可以區分不同的機器類型。如果絕對必要,請使用此對象的繼承,但不要對聚合本身使用繼承。

  2. 使用類繼承與ES的能力僅由串行器的限制。 ES並沒有規定數據如何被序列化,但如果你使用類似Protobuf或Newtonsoft.Json的東西,它們支持繼承。但是,在JSON的情況下,使用繼承確實在JSON輸出中放置了$ type屬性。

  3. 這取決於燃燒器是否需要獨立於爐的存在。如果不是,那麼它是爐體骨料的價值對象或實體部分,應該與爐體一起堅持。如果是的話,那麼它必須是一個聚合體,並且應該首先被創建並且然後被添加到熔爐中。這可以通過一個NSerivceBus傳奇來實現,其中AddBurnerToFurnaceCommand通過首先啓動相應的傳奇來處理,傳遞一個命令來創建一個Burner。一旦燃燒器被創建,創建燃燒器和熔爐之間的關聯。爐子只會引用Guid的燃燒器。在ES中,所有查詢通常都是通過預測來處理的,只有行爲通過ID爲規範聚合調用事件存儲。

+0

感謝您的幫助。是的,燃燒器獨立於爐子存在,它只是一個可以在熔爐之間切換的組件(所以它肯定有一個標識),並且可以被其他域對象直接引用(例如服務事件) – Max 2013-02-18 07:53:45