8

中的大多數服務代碼的時候我會是這樣的:MVC DDD:可以將存儲庫與控制器中的服務一起使用嗎?

public SomeService : ISomeService 
{ 
    ISomeRepository someRepository; 
    public Do(int id) 
    { 
     someRepository.Do(id); 
    } 
} 

所以它有點多餘

所以我開始在控制器中直接

是使用存儲庫這好嗎?有沒有像這樣的架構?

+1

實際上,我的代碼中沒有像這樣的傳遞示例。也就是說,存儲庫的目的之一是提供對單元測試目的進行模擬的能力,所以額外的抽象層可以僅僅因爲這個原因而有用。 – 2010-08-26 12:29:27

+0

@Robert針對控制器和模擬庫編寫測試有什麼問題?除了嘲笑控制器依賴 - 還有什麼其他服務會改變? – 2010-08-27 11:57:56

+0

@Arnis:我想我的意思是說,存儲庫從服務代碼中抽象出數據庫,所以如果你注入不同的存儲庫依賴關係,我想你可以稱之爲「模擬」。 – 2010-08-28 05:05:51

回答

5

你失去之間都存在業務邏輯的能力。

我不同意這一點。

如果業務邏輯是它應該是 - 在域模型,然後調用控制器(或更好的 - 使用模型綁定爲)回購得到聚合根和調用方法上似乎完全沒有給我。

當涉及太多技術細節時,應該使用應用程序服務,這會弄亂控制器。


我見過幾個人提到使用模型粘合劑到最近調入回購。這個瘋狂的想法來自哪裏?

我相信我們在這裏所說的2個不同的事情。我懷疑你的'模型聯編程序'意味着同時使用模型作爲一個視圖模型,並將UI中直接改變後的值直接返回給它(這本身並不是一件壞事,在某些情況下我會走這條路)。

我的'模型聯編程序'是一個實現'IModelBinder'的類,它需要構造函數中的倉庫(如果我們需要使用某些基本組合進行緩存,則可以擴展),並在調用操作之前使用它檢索聚合根並替換int idGuid idstring slugwhatever帶有真實域對象的動作參數。結合輸入視圖模型參數,我們可以編寫更少的代碼。事情是這樣的:

public ActionResult ChangeCustomerAddress 
(Customer c, ChangeCustomerAddressInput inp){ 
    c.ChangeCustomerAddress(inp.NewAddress); 
    return RedirectToAction("Details", new{inp.Id}); 
} 

在我實際的代碼,這是一個有點更復雜的原因,它包括的ModelState驗證以及可能來自於域模型的內部拋出一些異常處理(提取到再利用控制器擴展方法)。但不多。到目前爲止 - 最長的控制器動作約10行。

你可以看到工作實現(相當複雜和(對我來說)不必要的複雜)here

你只是在做Linq To Sql的CRUD應用程序或嘗試使用真正的域邏輯?

,你可以(希望)看,這種方法實際上幾乎迫使我們對task based應用,而基於CRUD一個移動。

這樣做在你的服務層的所有數據的訪問和使用IOC你可以得到許多像無形的緩存,事務管理,而我無法想象你與模型得到的粘合劑成分的容易組成AOP的好處。

...並有新的抽象層,邀請我們混合使用域的邏輯基礎設施和失去域模型的隔離。

請賜教。

我不知道我是否做過。我不認爲我自己開悟了。 :)


Here是我目前的模型活頁夾基類。 Here's來自我當前項目的控制器操作之一。並且here's「缺乏」商業邏輯。

+0

我見過幾個人提到使用模型粘合劑最近調用回購。這個瘋狂的想法來自哪裏?你只是使用Linq To Sql來做CRUD應用程序,或者嘗試使用真正的領域邏輯?通過在您的服務層中使用IOC進行所有數據訪問並使用IOC,您可以獲得AOP的諸多優勢,如隱形緩存,事務管理以及我​​無法想象使用模型綁定器輕鬆獲得的組件組合。請賜教。 – Ryan 2010-08-27 17:30:37

+0

@Ryan檢查我的答案 – 2010-08-27 21:45:48

+0

c.ChangeCustomerAddress(inp.Address) 此方法是否包含存儲庫調用以保存客戶? 如果是這樣,你如何在客戶注入庫? – mathieu 2010-08-27 21:49:49

2

如果您在控制器中使用存儲庫,您將直接從數據層轉到表示層。你失去了在兩者之間建立業務邏輯的能力。

現在,如果你說,當你需要的業務邏輯,將只使用服務,並使用存儲庫其他地方,你的代碼變成了一場噩夢。表示層現在正在調用業務層和數據層,並且您沒有很好的關注點分離。

我總是會走這條路:Repositories -> Services -> UI。一旦你不認爲你需要一個業務層,需求就會改變,你將不得不重寫所有事情。

+0

我不同意,業務邏輯不是全部或沒有。我不打算創建業務邏輯層,以防我可能需要業務邏輯。這是預優化。如果您遵守SOLID原則,那麼可以輕鬆處理需求變更。在沒有業務邏輯的情況下,從控制器調用存儲庫非常合適。如果需要更改和邏輯,請將存儲庫包裝到服務中並在控制器中調用新服務。 – 2010-08-27 22:15:39

+0

@你從哪裏認爲從控制器調用存儲庫禁止複雜的業務邏輯? – 2010-08-27 23:34:40

+0

@Chuck - 是的,YAGNI。但是,如果沒有某種業務邏輯,我從來沒有見過CRUD操作。 – Martin 2010-08-30 13:15:20

-2

即使使用「豐富的域模型」,您仍然需要一個域服務來處理涉及多個實體的業務邏輯。沒有一些業務邏輯,我也從來沒有見過CRUD,只是簡單的示例代碼。我總是喜歡馬丁的路線,以保持我的代碼簡單明瞭。爲DDD/MVC

+0

服務不應該有'業務邏輯'。這是實體和價值對象用於DDD的原因。 – 2016-12-19 17:27:44

0

我自己粗糙做法:

  • 控制器是應用特定的,因此他們應該只包含應用程序的具體方法,並調用服務的方法。
  • 所有的公共服務方法通常是原子事務或查詢
  • 只有服務實例&調用庫
  • 我的域名定義IContextFactory和IContext(大量泄漏抽象,IContext成員IDBSet)
  • 每個應用程序都有一個排序的Composition Root,這主要是實例化一個上下文工廠傳遞給服務(你可以使用DI容器,但不是什麼大不了的)

這迫使我保持​​我的業務代碼和數據交流放棄我的控制器。我覺得這是一個很好的紀律,因爲我不遵循上面的規定時,我有多鬆散!

+0

但是我也很欣賞這樣的論點:有些應用程序不保證調用服務只是爲了在單個實體上調用一些非常類似的方法。夠公平的,但是你必須決定你的交易在哪裏開始和結束。 – Chalky 2016-12-18 09:19:43

1

這是事情。

「業務邏輯」應該駐留在您的實體和值對象中。

存儲庫僅處理AggregateRoots。所以,直接在你的控制器中使用你的倉庫,你會覺得你把這個行爲當作你的「服務」來對待。此外,由於您的AggregateRoot可能只能通過其ID來引用其他AR,您可能必須調用一個以上的回購。它真的很快就變得討厭。

如果您打算提供服務,請確保您公開的是POCO,而不是實際的AggregateRoot及其成員。

您的回購不應該做任何操作,除了創建,檢索,更新和刪除的東西。您可能會根據特定條件進行一些自定義檢索,但這就是它。因此,在你的服務中有一個與你的服務相匹配的方法...代碼就在那裏。

您的服務是面向API的。想想這個......如果你要將這個服務包裝在一個.dll文件中供我使用,那麼你將如何創建你的方法,這對我來說很容易知道你的服務可以做什麼? Service.Update(對象)沒有多大意義。

我甚至沒有談到CQRS ......事情變得更有趣。

您的Web Api只是您服務的客戶端。您的服務可以被其他服務使用,對嗎?所以,考慮一下。你很可能需要一個服務來封裝AggregateRoots上的操作,通常是通過創建它們,或者從一個repo中檢索它們,對它做些什麼,然後返回一個結果。通常。

有意義嗎?

+0

是有道理的,它只是在大多數實體(db表)的許多應用程序中,我們所需要做的只是做一個簡單的crud,最後是repo服務和控制器具有完全相同名稱的方法 – Omu 2016-12-20 11:29:00

相關問題