我擔心DDD和PropertyChanged/CollactionChanged事件的組合現在可能是最好的主意。問題是,如果您將邏輯基於這些事件,則極難控制複雜性,因爲一個PropertyChanged會導致另一個和另一個PropertyChanged,並且很快就會失去控制權。
ProportyChanged事件和DDD並不完全相符的另一個原因是,在DDD中,每個業務操作都應該儘可能明確。請記住,DDD應該把技術性的東西帶入商業世界,而不是相反。並且基於PropertyChanged/CollectionChanged似乎不是很明確。
在DDD的主要目標是保持一致性內聚集,換句話說,你需要以這樣的方式的總和,即任何操作調用聚合是有效的,一致的(如果進程的操作成功)模型。
如果您建立的模型正確無需擔心「構建」事務 - 對聚合的操作應該是事務本身。
我不知道你的模型是怎麼樣的,但是你可能會考慮將聚合樹中的職責向上移動一層,很可能在流程中增加額外的邏輯實體,而不是依賴於PropertyChanged事件。
例子:
讓我們假設你有狀態,每當付款的變化,要重新計算的客戶訂單的總收支的集合。相反訂閱更改付款收集,並呼籲客戶的方法時收集的變化,你可能會做這樣的事情的:
public class CustomerOrder
{
public List<Payment> Payments { get; }
public Balance BalanceForOrder { get; }
public void SetPaymentAsReceived(Guid paymentId)
{
Payments.First(p => p.PaymentId == paymentId).Status = PaymentStatus.Received;
RecalculateBalance();
}
}
您可能已經注意到,我們重新計算單個訂單的平衡,而不是平衡整個客戶 - 在大多數情況下,這是可以的,因爲客戶屬於另一個總計,並且在需要時可以簡單地查詢其餘額。這正是表明這種'只在聚合內一致'的部分 - 我們現在不關心任何其他聚合,我們只處理單一的訂單。如果這不符合要求,那麼域名建模不正確。
我的觀點是,在DDD中,每種情況都沒有單一的好模型 - 您必須瞭解企業如何成功。
如果你看看上面的例子,你會發現沒有必要'建立'交易 - 整個交易位於SetPaymentAsReceived
方法。在大多數情況下,一個用戶操作應該導致一個具有聚合的實體的特定方法 - 該方法明確地涉及到業務操作(當然這種方法可能調用其他方法)。
對於DDD中的事件,有一個域事件的概念,但是這些概念與PropertyChanged/CollectionChanged技術事件沒有直接關係。域事件指示已經由聚合完成的業務操作(事務)。
全部測試似乎推動所有邏輯域模型使得 域模型相當複雜
當然有,因爲它是應該被用於與複雜的業務邏輯場景。然而,如果域名建模正確,那麼很容易管理和控制這種複雜性,這是DDD的優勢之一。
新增提供範例之後:有關創建一個名爲Project聚合根
好吧,什麼 - 當你從庫構建聚合根,你可以用NetworkData填充和操作可能是這樣的:
public class Project
{
protected List<Network> networks;
protected List<NetworkData> networkDatas;
public void Mutate(string someKindOfNetworkId, object someParam)
{
var network = networks.First(n => n.Id == someKindOfNetworkId);
var someResult = network.DoSomething(someParam);
networkDatas.Where(d => d.NetworkId == someKindOfNetworkId)
.ToList()
.ForEach(d => d.DoSomething(someResult, someParam));
}
}
NetworkEditor不會直接在網絡上運行,而是通過使用NetworkId的Project運行。
現貨。 DDD實體可以合法地報告屬性和集合變化,但僅限於外部觀察者(如表示代碼) - 從不用於域邏輯。 – jnm2