2013-11-21 38 views
1

我在這裏第一次接觸到DDD,大多數情況下,它似乎是好東西,但也有一些東西困擾着我。自我驗證和映射DTO和DDD

目前主要的是對象驗證自己的想法。

以前,我會寫一個類似的服務方法:

public class MyService 
{ 
    private IValidator _validator; 
    private IDomainMapper _domainMapper; 
    private IThingThatDoesSomething _thingThatDoesSomething; 
    private IResponseMapper _responseMapper; 

    public MyService(IValidator validator, IDomainMapper domainMapper, IResponseMapper responseMapper) 
    { 
     _validator = validator; 
     _domainMapper = domainMapper; 
     _responseMapper = responseMapper; 
    } 

    public ResponseDTO DoSomething(RequestDto requestDto) 
    { 
     if (_validator.IsValid(requestDto)) 
     { 
      var domainObject = _domainMapper.Map(requestDto); 

      var domainResponse = _thingThatDoesSomething.DoSomething(domainObject); 

      return _responseMapper.Map(domainResponse); 
     } 
     else 
     { 
      return new ResponseDTO { Valid = false, Errors = /* some error information */ }; 
     } 
    } 
} 

然而,誰花更多的時間是我學習DDD你的同事喜歡的驗證和映射功能坐域對象上。所以DTO看起來像:

public class RequestDto 
{ 
    public string Something {get; set; } 

    public DomainObject Map() 
    { 
     return new DomainObject { something = this.Something }; 
    } 

    public bool IsValid() 
    { 
     return this.Something == "something valid"; 
    } 
} 

這種感覺真的不對。首先,這個對象現在有多重責任,其次,從領域驅動的角度來看,這似乎是錯誤的,因爲我不希望一封信到達我的辦公桌,這個辦公桌宣稱自己是有效的或者不知道如何將自己轉換成別的東西。

有人可以解釋爲什麼這是好的DDD?

回答

2

首先,我認爲您的原始應用程序服務代碼看起來更好,但未應用您的同事建議,而且這完全不是DDD相關的。請記住,無論您是使用DDD還是編寫n層CRUD應用程序,基本編碼原則始終適用。我的意思是:

  1. 你有一個單獨的驗證類 - 這很好,因爲你可以重用它。
  2. 你有一個單獨的類來映射數據對象 - 這是很好的,因爲域對象不應該受到任何映射細節的困擾,特別是當它映射到數據對象時。

在另一方面也有可以在DDD方面做更好的幾件事情:

  1. 你的映射器顯然可以以兩種方式映射(從域對象的數據對象和另一週圍)。在DDD域中,對象正在工廠中創建/實現(沒有執行特定的工廠實現)或/和存儲庫中。重要的事實是域對象的創建是域本身的責任,而不是應用服務(如在你的代碼中)。

  2. 您正在使用驗證器驗證數據對象,但我不確定您是否在域中執行了相同的輸入驗證。在DDD中,許多人採用了可以用句子總結的方法:「永不讓你的域進入無效狀態」。我分享這種方法。在我的項目中,如果驗證邏輯很複雜,我傾向於爲實體設置單獨的驗證器。該驗證器由域實體自己用來驗證輸入參數。對於簡單的驗證(例如,空字符串檢查和空字符串檢查),我將它留在域對象中。至於你的數據對象驗證,大多數人(包括我在內)都傾向於儘可能「接近」用戶界面以獲得更好的用戶體驗(例如,帶有驗證錯誤的更快響應)。

還有一兩件事值得一提的是,通過你的最後的代碼段來看,它認爲你可能誤解了你的同事一點在一些點。你的RequestDTO類不是一個域對象,所以即使從你的同事那裏得到了一些建議,你也不應該在裏面放置驗證和映射邏輯。 DTO是數據持有者,僅此而已。

TL; DR版本

  1. 從一個域對象到數據對象映射是應用層(在一個單獨的映射類preffereably實現)的責任。
  2. 域對象不應映射到數據對象映射器在應用程序層。域對象的創建是域本身的責任(通過工廠)。
  3. 始終驗證數據到您的域。 永遠不要讓您的域名進入無效狀態。實體驗證邏輯應放置在域內。
+0

+1爲您的詳細和有益的答案!你會說有一個自我驗證的域,並且在應用層中有一個命令(DTO)的空值,範圍等的基本驗證是很好的。 (應用程序層由REST服務器使用) – danfromisrael

+0

@dansfromisrael:是的,您驗證傳入的DTO以確保客戶端遵守REST協議。但是,在一個域中,您還可以檢查業務規則,例如「如果客戶的帳戶餘額爲負值,則客戶無法創建新訂單」。兩者都會導致'_Bad Request_'被返回給客戶端。 –