2011-03-06 177 views
1

我正在查看來自http://code.google.com/p/ndddsample的偉大NDDDSample源以瞭解DDD。感到困惑的東西DDD示例:CargoRepository.Store()可用於控制器?

的CargoRepository有),這是由BookingService.AssignCargoToRoute()和CargoTrackingController.Search(稱爲find()方法:

Cargo cargo = CargoRepository.Find(trackingId); 

CargoRepository也有從BookingService稱爲存儲()方法.AssignCargoToRoute():

Cargo cargo = cargoRepository.Find(trackingId); 
if (cargo == null) 
{ 
    throw new ArgumentException("Can't assign itinerary to non-existing cargo " + trackingId); 
} 

cargo.AssignToRoute(itinerary); 
cargoRepository.Store(cargo); 

我的困惑是,似乎有什麼可調用CargoRepository.Store(),這將繞過在BookingService.AssignCargoTo業務邏輯停止CargoTrackingController路線()

爲什麼在DDD中允許這樣做?版本庫是否應該分成兩部分,一部分用於讀取application/ui/domain/service,另一部分用於寫入域/服務?

回答

2

在DDD中,服務不是所有業務邏輯的持有者。它們只代表動詞,與多個對象交叉關注的領域動作,因此不符合其中一個實體或聚合根源,而不會違反單一責任原則,併產生混淆實體的緊密耦合。

在您的示例中,Cargo.AssignToRoute(itinerary)和BookingService.AssignCargoToRoute()似乎是多餘的。這兩種將貨物綁定到路線的方式的存在會造成混淆。您可以保留它們中的任何一個,具體取決於您是否認爲貨物的責任是爲自己分配一條路線,或者是否使用不屬於它的功能重載實體。

除此之外,Controller直接調用Repository方法是完全合理的。服務不是控制器的單一訪問點。

+0

我一直在以錯誤的方式看域對象。我以爲我會打電話給oEntity.Load(someId),然後oEntity.DoSomething(x),然後oEntity.Save(),但是這將持久性的責任放在違反單一責任原則的實體中。實體只應該擁有自己的方法,並且在多個實體參與單個業務流程的情況下創建服務。我現在得到了更多的理解,謝謝。有趣的東西,謝謝 – 2011-03-07 19:19:30

1

那麼,我想這就是CQRS試圖實現的。

當然,在這種情況下繞過BL是一個壞主意(顯然很容易實現,甚至更糟糕)。但是你只是不能強制執行代碼中的所有規則,有些只會保留未在代碼中明確聲明的約定。一些不好的事情可能很難,但仍然不是不可能實現的,總會有很多愚蠢的錯誤。這就是編程的內容:你必須考慮自己在做什麼,否則沒有像DDD這樣的指導方針能夠幫助你實現目標。

+0

也許我對DDD的閱讀太多了,只需要相信常識以及採納指南。所以在這裏,我將存儲庫接口拆分爲兩個(ICargoRepositoryRead和ICargoRepositoryUpdate),並讓Controller訪問ICargoRepositoryRead接口 – 2011-03-07 10:24:12

1

爲了幫助您作爲開發人員維護一些易於理解和維護的結構,需要將應用程序與持久層和服務層分離,開發人員有責任按照某種模式正確使用代碼。

它不是限制你(開發人員)不正確使用它的框架,DDD是設計模式(指導如何組織你的應用程序結構)。

+0

謝謝,我現在明白DDD只是一個設計框架。所以在這種情況下,我必須假設控制器中的客戶端代碼儘可能地造成更多的損害,所以即使這個DDD樣本確實存在,我也不會給它一個具有更新功能的存儲庫。 – 2011-03-07 13:35:27

+0

@Gareth:服務巢穴是在內部使用,用於由創建Web Service的客戶端(例如,使用.NET中的WCF)的客戶端使用的外部服務,該服務通常基於您的服務巢穴,並且您可以在其中定義服務層的哪些方法暴露給客戶端,並控制權限(授權)。 – 2011-03-07 13:58:18