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;
            }
        }
    }
}
4

2 回答 2

3

与其拥有这种类似枚举的类型(UserType),为什么不将这些角色演变成完全成熟的对象呢?您关心的是用户扮演的角色,而不是特定用户。这会将用户确实是供应商或请求者的身份验证和验证推送到上层(嗯,实际上是调用代码,在这种情况下可能是某种应用程序服务)。下面是一个非常粗略的第一次迭代:

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 仍有很多“难闻的气味”,但这是一个开始。

于 2013-05-06T20:44:06.647 回答
2

这受到 Yves answer 和您对它的回复的启发。

我个人的口头禅是将隐含的事情明确化,因为我喜欢应用此原则后代码的结果:

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;
     }
}
于 2013-05-11T07:55:56.460 回答