2

在我們的應用程序中,我們有一個場景,我們需要根據業務規則和當前用戶的上下文來驗證屬性更新。我正在嘗試確定進行驗證的最佳方式,因爲我認爲域模型不應該瞭解當前用戶。我們的正常授權與域分開,與此場景不同。上下文域驅動模型驗證

這個驗證應該發生在哪裏,並且有更好的方法來處理它?域模型應該知道用戶?任何幫助或輸入讚賞。

簡單示例: 我們訂購的批准數量。只有特定的用戶類型才能在特定的方向上更新數量。這是在域聚合中驗證的正確方法嗎?

public enum UserType 
{ 
    ViewUserType, 
    RequesterUserType, 
    SupplierUserType 
} 

public class Order 
{ 
    public int OrderId {get; private set} 
    public int RequestedQuantity {get; private set} 
    public int ApprovedQuantity {get; private set} 

    public void RequestQuantity(int quantity, UserType userType) 
    { 
     if (userType == UserType.RequesterUserType) 
     { 
      this.RequestedQuantity = quantity; 
     } 
    } 

    // Question: The direction that the approved quantity can change is a business rule 
    // but directly deals with the context of the user. Should the model know about the user 
    // or should this validation be pulled out to either the application service, a model extension, 
    // or maybe a specification? 
    public void ApproveQuantity(int quantity, UserType userType) 
    { 
     if (userType == UserType.RequesterUserType) 
     { 
      if (quantity <= this.ApprovedQuantity) 
      { 
       // Requester type user can only update if lowering the approved quantity 
       this.ApprovedQuantity = quantity; 
      } 
     } 
     else if(userType == UserType.SupplierUserType) 
     { 
      if (quantity >= this.ApprovedQuantity) 
      { 
       // Supplier type user can only update if increasing the approved quantity 
       this.ApprovedQuantity = quantity; 
      } 
     } 
    } 
} 

回答

2

這是從伊夫的回答和你對它的回覆中略微得到啓發。

我個人的口頭禪是讓含蓄的東西明確的,因爲我喜歡這個準則後的代碼原來的方式:

public interface IProvideCurrentIdentityRoles 
{ 
    bool CanRequestQuantity() 
    bool CanApproveQuantity(); 
    bool CanOverruleQuantityOnSubmittedOrder(); 
    bool CanIncreaseQuantityOnFinalOrder(); 
    bool CanDecreaseQuantityOnFinalOrder(); 
} 

public class Order 
{ 
    public int OrderId {get; private set} 
    public int RequestedQuantity {get; private set} 
    public int ApprovedQuantity {get; private set} 

    public void RequestQuantity(int quantity, IProvideCurrentIdentityRoles requester) 
    { 
     Guard.That(requester.CanRequestQuantity()); 
     this.RequestedQuantity = quantity; 
    } 

    public void ApproveQuantity(int quantity, IProvideCurrentIdentityRoles approver) 
    { 
     if (quantity == this.RequestedQuantity) 
     { 
      Guard.That(approver.CanApproveQuantity()); 
     } 
     else 
     { 
      if (orderType == OrderType.Submitted) 
      { 
       Guard.That(approver.CanOverruleQuantityOnSubmittedOrder()); 
      } 
      else if (orderType == OrderType.Final) 
      { 
       if (quantity > this.ApprovedQuantity) 
       { 
       Guard.That(approver.CanIncreaseQuantityOnFinalOrder()); 
       } 
       else 
       { 
       Guard.That(approver.CanDecreaseQuantityOnFinalOrder()); 
       } 
      } 
     } 
     this.ApprovedQuantity = quantity; 
    } 
} 
3

取而代之的是這種枚舉類型(UserType),爲什麼不將這些ROLES演化爲完全成熟的對象呢?用戶扮演的角色是您關心的角色,而不是特定的用戶。這將認證和驗證推到用戶確實是SUPPLIER或REQUESTER到上面的層(實際上,調用代碼,在這種情況下可能是某種應用程序服務)。下面的是什麼可能看起來像一個非常粗略的,第一次迭代:

public class Order { 
    public void RequestQuantity(int quantity, UserType userType) 
    { 
    this.RequestedQuantity = quantity; 
    } 

    public void ApproveToLowerOrEqualQuantity(int quantity) { 
    if (quantity <= this.ApprovedQuantity) 
    { 
     // Requester type user can only update if lowering the approved quantity 
     this.ApprovedQuantity = quantity; 
    } 
    } 

    public void ApproveToHigherOrEqualtQuantity(int quantity) { 
    if (quantity >= this.ApprovedQuantity) 
    { 
     // Supplier type user can only update if increasing the approved quantity 
     this.ApprovedQuantity = quantity; 
    } 
    } 
} 

//Calling code 
public class ApplicationServiceOfSomeSort { 
    public void RequestQuantity(UserId userId, OrderId orderId, int quantity) { 
    var requester = requesterRepository.FromUser(userId); 
    requester.MustBeAbleToRequestQuantity(); 

    var order = orderRepository.GetById(orderId); 
    order.RequestQuantity(quantity); 
    } 

    public void ApproveQuantityAsRequester(UserId userId, OrderId orderId, int quantity) { 
    var requester = requesterRepository.FromUser(userId); 
    requester.MustBeAbleToApproveQuantity(); 

    var order = orderRepository.GetById(orderId); 
    order.ApproveToLowerOrEqualQuantity(quantity); 
    } 

    public void ApproveQuantityAsSupplier(UserId userId, OrderId orderId, int quantity) { 
    var supplier = supplierRepository.FromUser(userId); 
    supplier.MustBeAbleToApproveQuantity(); 

    var order = orderRepository.GetById(orderId); 
    order.ApproveToHigherOrEqualQuantity(quantity); 
    } 
} 

當然,還是有不少「難聞的氣味」圍繞這一API,但它是一個開始。

+0

感謝您的反饋伊夫。 'requester.MustBeAbleToApproveQuantity()'方法的意圖是檢查動作是否被允許,並拋出異常或返回一個布爾結果如果不允許該動作? 現在我在應用程序層有訂單服務。服務器使用IOrderAuthorizer來確定用戶所處的角色。然後,我會爲已批准的數量進行更新。 – user2354863 2013-05-07 02:03:57

+0

要增加更多複雜性,如果存在多個狀態:草稿,提交和最終狀態會怎樣。在提交狀態下,請求者可以以任何方式更新批准的數量,但在最終狀態下,它們只能降低它(如簡單示例)。這會改變你解決問題的方式嗎? – user2354863 2013-05-07 02:04:30

+0

MustXXX方法拋出我的例子。 – 2013-05-07 14:34:36