2016-11-11 108 views
1

我有一個租用實體,它是一個聚合根。除此之外,它還維護一個分配列表(保留的時間塊)。何時以及爲什麼要使用域服務?

如何添加新的分配?由於Rental是聚合根,所以任何新的分配都應該經過它,但在我們嘗試將分配保存在數據庫中之前,無法說明是否可以分配租賃。另一位用戶可能在此期間保留了它。我猜測,我應該爲此使用域服務?

我不願意注入任何東西每次我需要一個新的租賃但注入域服務,而不是一個存儲庫之間的區別,除了術語是不同的?

+0

您的系統非常龐大,您需要負載平衡並運行您的域邏輯的各種實例嗎?如果不是這樣,那麼每個客戶端都將通過您的有界上下文的相同實例進行租用,並且可以在您的域邏輯代碼中解決衝突,而與數據庫寫入無關。 –

+0

是的。我們正在使用微服務架構,因此係統旨在同時運行預訂服務的多個實例。 – Novac

回答

2

何時以及爲什麼要使用域服務?

您使用域服務來允許聚合運行查詢。計稅是一個不時顯示的例子。彙總將某些狀態傳遞給計算器,計算器報告稅金,彙總決定如何處理該信息(忽略它,拒絕需要它的更新等)。

運行查詢不會以任何方式修改域服務實例,因此您可以隨心所欲地重複查詢,而無需擔心計算會互相影響。

認爲只讀服務提供商。

由於Rental是聚合根,所以任何新分配都應該經過它,但在我們嘗試將分配保存到數據庫之前,不可能說是否可以分配租賃。另一位用戶可能在此期間保留了它。我猜測,我應該爲此使用域服務?

否 - 完全錯誤的用例。

如果分配是租賃彙總的一部分,那麼租賃彙總可以創建自己的分配也可以。您不需要爲此提供服務(如果您喜歡分離問題,可以將工作委託給工廠)。

如果「另一個用戶可能在此期間保留了該分配」,則表明存在爭用 - 兩個用戶試圖同時更改相同的聚合。這通常以兩種方式之一進行管理。

鎖定:您只允許一個用戶每次修改租賃彙總。因此,在數據競賽中,失敗者必須等待勝利者完成,然後聚合可以拒絕失敗者的命令,因爲已經採用了該特定分配。

樂觀併發:您允許兩個用戶同時修改聚合的不同副本,但只有原始狀態不變時才允許保存。認爲「比較和交換」;比賽是在保存,這兩個指令

state.compareAndSwap(originalState, loserState) 
state.compareAndSwap(originalState, winnerState) 

之間

得主的比較和交換成功,但失敗者的失敗(因爲originalState!= winnerState),所以失敗者修改被拒絕。

無論哪種方式,只允許一次寫入數據庫保留分配。

如果我的理解正確,您是說在這種情況下可以使用租賃域實體內部的存儲庫嗎?

不,您不應該需要 - 作爲租賃聚合的一部分的分配由內存中的聚合創建,並且在保存聚合時首先出現在數據存儲中。

爲什麼要使用聚合,如果所有結果都必須提取到周圍的代碼或工廠中?

這裏的一些答案是關注點分離 - 聚合的主要關注點是強化業務不變性:確保創建具有某種特定狀態的分配與其他所有事情保持一致。工廠負責確保創建的對象正確連接。

要使用您的示例:工廠將負責在內存中創建分配,但不需要知道確保分配是唯一的任何內容。確保分配是唯一的規則由彙總進行描述和執行。

+0

如果我的理解正確,你是說在這種情況下,可以使用租賃域實體內的存儲庫嗎?我們正在運行這些服務的多個實例,因此在代碼級別的任何鎖定都不起作用。我可以研究樂觀的併發性,但是我的領域模型感覺有障礙。我對域實體的操作變得無關緊要,因爲任何狀態更改或返回的值都是猜測,直到周圍的代碼檢查數據庫爲止。如果所有的結果都被提取到周圍的代碼或工廠中,爲什麼要使用聚合? – Novac

+0

我仍然不完全確定我想如何處理我的具體問題,但現在我知道不該做什麼。謝謝。 – Novac

0

使用靜態工廠方法創建租賃對象。

public static class RentalFactory 
{ 
    public Rental CreateRental() 
    { 
     var allocationSvc = new RentalAllocationService(); 
     return new Rental(allocationSvc); 
    } 
} 

存儲庫只應該關注底層存儲的持久性。 域服務首要關注的是執行一些涉及實體或值對象的行爲。

+0

但是在這種情況下檢查然後保存是不可靠的。爲了讓Rental集合返回任何可用的內容,它必須嘗試將新的分配寫入數據庫 - 意思是試圖持續這些信息。否則,Rental.Allocate方法將只是「添加到內部列表並且交叉手指」。 – Novac

相關問題