2011-12-06 51 views
5

我的編程語言是C#。我有一個關於我的域模型中的持久性無知的問題。持久的無知域圖層

讓我們假設我有一類人,像這樣:現在

public class Person 
{ 
    private string email; 

    public string Email 
    { 
     get { return email; } 
     set { email = value; } 
    } 

    public Person(string email) 
    { 
     this.email = email; 
    } 
} 

,我的域模型中,有一個規則,不可能有具有相同的電子郵件地址的兩個人。因此,在實例化新人時,需要驗證以及更改電子郵件屬性時。所以我想知道你將如何在你的持久性無知域圖層中解決這樣的驗證。我目前所做的是使用工廠模式進行人員實例化,在該實例中我注入了人員存儲庫。在那裏,我可以使用相同的電子郵件地址搜索其他人。像這樣:

public class PersonFactory 
{ 
    private static readonly IPersonRepository personRepository; 

    public Person CreateNewPerson(string email) 
    { 
     Person personWithSameMail = personRepository.GetPersonByEmail(email); 

     if (personWithSameMail != null) 
      throw new ApplicationException("Email already exists."); 

     return new Person(email); 
    } 

    public PersonFactory(IPersonRepository personRepository) 
    { 
     this.personRepository = personRepository; 
    } 
} 

但改變人的電子郵件地址(可以是一個有效的商業案例)時,使用此解決方案,檢查仍不能覆蓋。此外,Person類仍然暴露一個公共構造函數,並繞過工廠,但仍然有可能重複郵件地址的人員。

任何解決這個問題的解決方案?

P.S.將所有數據中心的人:不,我不想要驗證重複數據刪除電子郵件的數據訪問層)

UPDATE:

也許這整個問題是過時的反正。根據域模型上下文檢查重複的電子郵件總是需要知道所有人的「某事」 - 根。 「東西」可以是地址簿,也可以是包含所有具有電子郵件地址的人的整個世界。因此,也許我正在混淆程序員需要技術上優雅的問題解決方案,這只是因爲缺乏完整和深思熟慮的域模型而存在。這可以在這裏嗎?這不僅僅是一個有電子郵件地址的人在空間中漂浮(嘿,空間將成爲我在這裏的聚集根;))只是爲了存在的樂趣?但是,如果這將是一個像地址簿應用程序這樣的真實商業案例,則地址簿將成爲人員的聚合根,因此可以檢查其內部收集中的所有人以確保沒有重複的電子郵件地址。

+0

爲什麼不讓內部構造函數和更新時檢查電子郵件地址?我不認爲這是一個給工廠存儲庫的好方法。調用工廠的服務功能應該檢查電子郵件地址是否已經存在。 –

+0

@WouterdeKort:我不同意你的評論:(1)讓ctor內部不起任何作用。它仍允許創建具有重複郵件地址的用戶。 (2)使調用工廠的方法進行檢查,有效地移除該業務規則。現在由呼叫者來執行這個規則。這只是非常糟糕的API設計 –

+0

@DanielHilgarth他明確提到公共構造函數是一個問題。工廠應該構建一個包含所有依賴項和所需值的對象。混合業務邏輯與工廠是我稱之爲不好的設計。 –

回答

2

我不是DDD專家,但我認爲它是這樣的。

首先,對我來說,設計中最大的缺陷是允許實體上的setter。這意味着,如果沒有聚合根知道您的實體的狀態,您可以更改。我會重構它去除setter,並讓它通過創建對象時的構造函數進行設置。

另一點。個人實體不應該對電子郵件進行驗證(以檢查電子郵件是否已被使用的形式),因爲如果她是聚合的根,它只能意識到它自己的狀態和相關的子實體。然後你應該從實體中引用存儲庫,這對我來說是不好的設計。這就是爲什麼你使用了我認爲的工廠。

我認爲驗證首先應該在UI中發生,儘可能快地失敗。但這還不夠。當堅持你的域名狀態時,你應該強制規定人員有唯一的電子郵件。我認爲驗證應該發生在例如域名服務,稱爲PersonRegistrationService,將有到IPersonRepository和添加的人實體的集合堅持之前的基準,它會首先檢查人員的電子郵件是獨特。如果沒有,我會通知用戶一個錯誤,而不是添加實體。

您認爲如何?

+0

正如我所理解的那樣,創建一個人應該是域內部的。然後,會有一個註冊服務,這種行爲類似於驗證某人甚至與該域存在關係的行爲,是正確的嗎?因此,該服務將獲得所有必需的初始人員屬性作爲參數,然後通過注入存儲庫,可以照顧「是否允許存在給定數據的人」? – Chris

+0

我認爲服務首先是一種領域概念。我建議註冊服務機構,因爲從空氣中創造人對我沒有意義。因此,該服務的責任是接受參數(或者甚至是在此時刻不屬於域的狀態的新實體實體),如果電子郵件是唯一的,則向存儲庫驗證,然後將該人添加到其中內部收集(這將由ORM或其他人保存,但這不僅僅是重要)。 –

+0

也許其他人有另一個承擔這一點,但通過域服務似乎是合理的。事實上,它與您的工廠非常相似,但不同之處在於該服務具有域名含義,並在成功驗證後將該人員添加到存儲庫(這是持久存儲的Person實體的集合) –