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) を持つ代わりに、これらの 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 にはまだ多くの「悪臭」がありますが、それは始まりです。

于 2013-05-06T20:44:06.647 に答える
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;
     }
}
于 2013-05-11T07:55:56.460 に答える