2016-03-04 88 views
0

如果有以下代碼。DDD工廠責任

public class CountryFactory : IEntityFactory 
{ 
    private readonly IRepository<Country> countryRepository; 

    public CountryFactory(IRepository<Country> countryRepository) 
    { 
     this.countryRepository = countryRepository; 
    } 

    public Country CreateCountry(string name) 
    { 
     if (countryRepository.FindAll().Any(c => c.Name == name)) 
     { 
      throw new ArgumentException("There is already a country with that name!"); 
     } 

     return new Country(name); 
    } 
} 

從DDD方法,是創建一個Country的正確方法。或者是否有更好的辦法來檢查一個國家是否存在,如果不存在,只需致電工廠返回一個新的實體。這意味着該服務將負責堅持實體而不是工廠。

我有點困惑,責任應該放在哪裏。特別是如果需要創建更復雜的實體,這不像創建一個國家那麼簡單。

+1

我認爲這個問題可能來自您使用的詞彙。 * create *方法實際上是一個具有默認值的查找,如果它不存在的話...它不是真正的*創建* ...因此我覺得很難認爲它是無處不在的語言的一部分。如果不知道該實體是如何使用以及與什麼相關的,我發現很難說其他任何東西,因爲有時邏輯可能位於域服務,應用程序服務,工廠,存儲庫或只是一個*新實例*,具體取決於情況。 – Augusto

+1

嗯,我真的需要知道將回購注入工廠是否有效/良好實踐。所有的實體是否都有製造它們的工廠?它真的下降了,我是否創建了一個基於持久化的實體,或創建實體,試着堅持它,並擔心它是否出現錯誤。 –

回答

1

注入庫到廠是好的,但它不應該是你的第一個問題。起點應該是:您的業務領域需要什麼樣的一致性?

通過檢查CountryFactory國家名稱的單一性,是您的域層的一部分,你給自己的印象是,國家將始終是一致的。但唯一的總和是Country,並且因爲沒有AllCountries聚合體充當一致性邊界,所以不能保證對這個不變性的尊重。有人可以隨時潛入一個新的國家,這個國家的名稱與剛剛添加的國家完全相同,只是在您檢查完畢後。你可以做的是包裹CreateCountry操作成(如果你使用RDBMS,從而使整個表),這將鎖定整組的國家,但這會傷害併發事務。

還有其他選擇需要考慮。

  • 爲什麼不利用數據庫唯一約束來強制國家/地區名稱不變?作爲補充,您還可以在UI級別設置另一個檢查點,以警告用戶輸入的國家/地區名稱已被使用。這將需要另一種「查詢」服務,只是調用CountryRepository.GetByName()但如果不希望返回的國家進行修改。

    很快你會意識到有兩種模式 - 一種可以在特定時刻爲您提供一些域數據,以便您可以在用戶界面上顯示它,另一種可以顯示操作( AddCountry),並保證域不變量始終保持不變。這是邁向CQRS的第一步。

  • 正在添加或修改國家的頻率是多少?如果真的很高,我們是否真的需要一個國家名稱在任何時候都是獨一無二的?如果我們放寬了限制並允許用戶臨時創建重複的國家名稱,它不會解決很多問題嗎?一種機制可以在稍後檢測到重複項並採取補償措施,將新增加的國家暫時擱置並向用戶伸出手,要求他們更改名稱。 A.k.a最終一致性而不是直接一致性。

  • Country需要是一個聚合?如果它是一個價值對象,並且在使用它的每個實體中重複,那麼成本是多少?

+0

@Shane Van Wyk你有沒有想到最終?我對Guillaume31的關於域實體不變的觀點有所瞭解,但是當需要唯一的約束並且沒有辦法使它成爲Value Object時,它應該如何處理呢? – Sergio

1

DDD工廠用於封裝複雜對象和聚合創建。通常,工廠不是作爲單獨的類實現的,而是作爲返回新的聚合的聚合根類的靜態方法實現的。

工廠方法比構造函數更適合,因爲您可能需要具有用於序列化目的的技術構造函數,並且var x = new Country(name)在無處不在的語言中的含義很少。這是什麼意思?爲什麼創建一個國家時需要一個名字?您是否真的創建了國家,新國家出現的頻率如何,您是否甚至需要對此流程進行建模?如果你開始考慮你的模型和無處不在的語言,除了戰術模式之外,所有這些問題都會出現。

工廠必須返回有效的對象(即集合),檢查其內部的所有不變量,但不在外部。工廠可能會接收服務和存儲庫作爲參數,但這也不是很常見。通常,您有一個應用程序服務或命令處理程序來執行一些驗證,然後使用工廠方法創建一個新的聚合並將其添加到存儲庫。

還有由利Gorodinski這裏Factory Pattern where should this live in DDD?

一個很好的答案此外,實施工廠在Red Book的第11章詳盡地描述。