我的問題是,我是否需要AddItem函數接收存儲庫作爲第二個參數,並拋出異常,如果服務不存在數據庫中?
簡答:當然,爲什麼不呢?
較長的答案...
如果服務和發票都是相同集合的一部分,那麼倉庫是不必要的 - 只是看總的狀態。所以接下來假定在發票和服務之間有一個事務邊界。
使用存儲庫作爲參數是有點太多的東西 - 發票並不需要加載的服務,它只是需要知道服務存在。因此,您可以使用支持「該服務是否存在?」的DomainService而不是將方法簽名放入方法簽名中。查詢。 (DomainService的實現可能在存儲庫中進行查找 - 我們在這裏沒有做到魔術,我們只是將發票與實現細節隔離開來,它不需要知道)。
在簽名文檔中使用更具限制性的接口,明確了這些組件之間的集成協議。
那就是說,要求是非常可疑的。如果服務和發票處於不同的集合中,那麼它們可能具有不同的生命週期。當您嘗試加載發票時應該會發生什麼,其中包含引用不再存在的服務的項目?這個用例是否應該爆炸?如果是這樣,將很難編輯發票來解決問題....
如果,當您將項目添加到發票,某個其他線程正在刪除服務...?
回顧Udi Dahan的散文:Race Conditions Don't Exist。執行摘要 - 如果您的模型對時間的微秒變化很敏感,那麼您可能不會對業務建模。
爲了保護這個「不變」,你至少有三種其他的選擇。
一個在客戶端;如果你不讓客戶產生無效的服務代碼,那麼你不會有這個問題。輸入驗證屬於客戶端組件或應用程序組件中,而不是模型。也就是說,當應用程序通過跨過流程邊界的DTO構造ServiceCode時,可能會檢查這種情況。
一個是模型的下游 - 如果您可以檢測到引用無效的服務代碼的發票項目,那麼您可以廣播一個例外報告,並使用應急響應流程來管理該問題。一致性問題很少見,易於檢測,易於修復,不需要域模型中的嚴格驗證。
一個在模型本身之內 - 如果發票項目的創建與服務的生命週期密切相關,那麼可能該項目是由服務創建的,而不是由發票創建。例如
class Service {
reportUsage(Customer, TimePeriod)
}
不會是一個不尋常的簽名看,你可能可以確信的是,服務養域事件是要正確地報告自己的ServiceCode。
您是否考慮過使用ServiceFactory並在那裏驗證服務? – Cerad
服務是一個聚合根嗎? – plalx
您無需等到物品被添加到發票中。如果服務無效(在系統中不存在),創建服務對象本身應該失敗 – falcon