4

我已經在不同的地方看,在DDD一個重要的要求是具有存儲庫的合同有界:DDD:存儲庫合同

findByName(string name) 
findByEmail(string email) 
etc. 

而不是提供一個通用查詢接口:

findBySpecification(Specification spec) 

我明白爲什麼這很重要:能夠模擬Repository進行測試或更改基礎持久性框架。

雖然這個規則在整個應用程序中並不是很難執行,但我無法弄清楚在爲用戶提供「高級搜索」表單時如何執行它。

比方說,我有一個表格,允許通過關鍵詞搜索博客文章,通過日期,通過作者

這些標準是自由組合的,我顯然不能提供方法爲每個用例:

findByKeyword(string keyword) 
findByDateRange(Date from, Date to) 
findByKeywordAndDateRange(string keyword, Date from, Date to) 
findByDateRangeAndAuthor(Date from, Date to, User author) 
etc. 

我是否缺少某些東西或者它是規則的例外之一嗎?

回答

2

Specification作爲參數傳遞給存儲庫沒有任何問題。這實際上是處理存儲庫接口上方法爆炸的一種非常好的方法。看看這個answer。 '過濾'可能比「高級搜索」場景中的「規範」更合適。我覺得這個代碼將不會違反任何DDD準則:

Filter filter = new FilterBuilder() 
    .WithinDateRange(dateRange) 
    .IncludingKeywords("politics", "news") 
    .ByAuthor("John Smith") 
    .Build(); 

blogs.FindByFilter(filter); 

注意,創建過濾器可以住域之外的代碼。因爲它不會違反任何域規則。如果有一條規則,如「匿名發佈者發佈的博客應該由主持人」?雖然它可以用Filter來表達,但這樣做會使業務邏輯具有外部性。它會更有意義,把這個規則到域代碼,並有這樣一個專門的倉庫方法:

blogs.RequireModeratorAttention(); 
1

Repository模式有兩大好處:

  1. 它從你的持久化層解耦應用程序和成語。
  2. 它集中並限制了對明確定義和理解的域段的數據訪問(存儲庫中的數據訪問方法具有定義明確的結果且可合理測試)。

如果您使用持久層提供的規範模式的實例(例如NHibernate Criteria),那麼您會否定好處之一。完全使用規範模式(即使是自己推出的規範模式)也會降低第二個優點。

這就是說,在某些情況下,如搜索界面,規範是必要的 - 只要確保並推出自己的。

1

雖然這條規則並不難,整個 申請強制執行,我無法弄清楚如何當談到 提供的「高級搜索」形式向用戶強制執行。

實際上,如果您需要的只是一個搜索表單,您不必支付所有這些抽象的成本。存儲庫(至少在DDD環境中)旨在從業務邏輯(應用程序層)中抽象出持久性框架的細微差別。

如果您有改變用戶地址的命令,最好有一個使用FindUserById方法的存儲庫,而不是在應用層中有一些神奇的Hibernate代碼。有一個你可能想測試與持久層 嘲笑

  • 應用層(庫)應用層兩個原因

    • 是你關心 因爲它的業務邏輯

    你的東西不需要所有這些僅僅爲UI獲取一些數據。我會建議使用專門的'Finder'類,甚至可能生活在UI層。它們可以在抽象的「規範」上運行,或者在裸Hibernate(或者你最喜歡的ORM)上運行(甚至更好)。我寫了一篇關於這種方法的博客文章here