是否允許客戶端代碼引用非根集合內的實體?我有一個Story
(根),Team
(實體)和TeamMember
(實體)。我試圖確定AddTeamMember
方法是否屬於Team
或Story
。基本集合問題
我想我的例子有點誤導。我真正的問題是客戶端代碼可以在一個聚合中引用非根實體嗎?
是否允許客戶端代碼引用非根集合內的實體?我有一個Story
(根),Team
(實體)和TeamMember
(實體)。我試圖確定AddTeamMember
方法是否屬於Team
或Story
。基本集合問題
我想我的例子有點誤導。我真正的問題是客戶端代碼可以在一個聚合中引用非根實體嗎?
我的意見 - 它不應該。引用屬於某個聚合的實體意味着您可以在沒有完全聚合上下文的情況下調用該實體上的方法,並且如果允許該方法,則無法確定整個聚合是否有效且一致。
簡單的例子:
public class MyAggregateRoot
{
protected MyEntity entity;
public void BuildUpAggregate()
{
ValidateSomeRule();
LoadEntityFromDatabase();
}
public MyEntity MyEntity
{
get
{
VerifySomeOtherRule();
return entity;
}
}
}
正如你所看到的,同時建立和檢索通過聚合根myEntity所,我們有兩個驗證規則檢查 - 如果你將允許客戶直接引用myEntity所,總可能會改變客戶端檢索到實體並對其執行操作之間的時間,因此檢查將不再有效,但您不會意識到這一事實。換句話說,你的聚合將是不一致的,並且可能是無效的。
一般來說,在DDD有,指出在骨料實體的所有訪問應該從聚合根遍歷進行強烈的規則 - 這個規則正是集料的一致性的緣故。
這就是說,你的客戶端可以參考實體的投射 - 一種只讀副本只包含用於顯示和決定某個動作是否在目前情況下提供所需的數據。您可以更進一步,將來自一組實體的數據聚合到一個投影中,稍微調整它,以便根據UI的要求進行調整。我發現這種技術對於不允許我的用戶界面決定如何建模業務域非常有用。
不知道你的架構應該如何工作,它聽起來應該是Team
而不是Story
。假設你有一對多從Team
到Team Member
,而Team Member
是Team
對象的子對象,而不是Story
。
假設「團隊」有一個或多個「團隊成員」。 – Tejs
糟糕。你說孩子,我不知何故閱讀子類。別介意我的評論:) –
團隊應該與團隊成員有「有」關係。故事和團隊成員彼此沒有直接關係。
類應該是這樣的:
class team
{
list<TeamMember> teamMembers;
void AddTeamMember(TeamMember member){}
}
另一個原因,團隊必須添加團隊成員方法,如果方法是故事的一部分,那麼你必須在你想添加部件,其團隊明確提及。
addteamMember(Team T, TeamMember member);
根應該提供正確的方法來訪問非根元素(第一級嵌套)。在你的情況下,團隊應該有addTeamMember方法,故事應該有一個方法(AddMemberToTeam(team t,teammember m)),它調用指定團隊的addTeamMember方法。
+1你認爲通過隱藏所有非聚合根實體,像C#'內部'這樣的東西來強制執行它是有意義的嗎? – Dmitry
@Dmitry:雖然我看到了這種限制的好處,但我寧願在概念層面上強制執行它 - 我傾向於做的僅僅是爲聚合根創建存儲庫,並引入一條規則,即只能通過存儲庫檢索實體。隱藏在'內部'的東西是讓測試變得更加困難,並且它強化了你項目的物理結構(我知道,你可以在AssemblyInfo中設置內部類的可見性,但我認爲它不過是一種解決方案)。另外,創建代理或者模擬很困難。當然,這種方法也取決於你的團隊的成熟度。 – kstaruch