2

次のビジネス ルールを持つプロジェクト割り当てドメインがあります。

  1. 新しい従業員がプロジェクトに割り当てられるとき、総支出は予算額を超えてはなりません。
  2. 従業員の場合、割り当て率の合計は 100% を超えてはなりません

で作成した以下のエンティティを作成しましたC#

質問

ロジックは、AllocateProject と Employee の 2 つのクラスに分割さList<Allocation>れます。クラスのプロパティとして追加するのではなく、パラメーターとして Allocate メソッドに渡されます...正しいアプローチですかList<Allocation>、これら 2 つのクラスにプロパティとして追加する必要がありますか? ?

ノート:

データベース

ここに画像の説明を入力

資格

ここに画像の説明を入力

コード

計画

 public class Project
    {
        public int ProjectID { get; set; }
        public int BudgetAmount { get; set; }
        public string ProjectName { get; set; }

        public void Allocate(Role newRole, int newPercentage, Employee newEmployee, List<Allocation> existingAllocationsInProject)
        {
            int currentTotalExpenditure = 0;
            if (existingAllocationsInProject != null)
            {
                foreach (Allocation alloc in existingAllocationsInProject)
                {
                    int allocationExpenditure = alloc.Role.BillRate * alloc.PercentageAllocation / 100;
                    currentTotalExpenditure = currentTotalExpenditure + allocationExpenditure;
                }
            }

            int newAllocationExpenditure = newRole.BillRate * newPercentage / 100;
            if (currentTotalExpenditure + newAllocationExpenditure <= BudgetAmount)
            {
                List<Allocation> existingAllocationsOfEmployee = GetAllocationsForEmployee(newEmployee.EmployeeID);
                bool isValidAllocation= newEmployee.Allocate(newRole, newPercentage, existingAllocationsOfEmployee);

                if (isValidAllocation)
                {
                    //Do allocation
                }
                else
                {
                    throw new Exception("Employee is not avaiable for allocation");
                }

            }
            else
            {
                throw new Exception("Budget Exceeded");
            }

        }
    }

従業員

public class Employee
{
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }


    public bool Allocate(Role newRole, int newPercentage, List<Allocation> existingAllocationsOfEmployee)
    {
        int currentTotalAllocation = 0;
        if (existingAllocationsOfEmployee != null)
        {
            foreach (Allocation alloc in existingAllocationsOfEmployee)
            {
                currentTotalAllocation = currentTotalAllocation + alloc.PercentageAllocation;
            }
        }

        if (currentTotalAllocation + newPercentage <= 100)
        {
            return true;
        }

        return false;
    }

    }

参考文献

以下は、ORM のないリポジトリ パターンからのものです。

顧客が注文のリストを持っている必要があるのはどのような行動ですか? ドメインの動作 (つまり、どの時点でどのデータが必要か) をさらに検討すると、ユース ケースに基づいて集計をモデル化でき、オブジェクトの小さなセットの変更追跡のみを行うため、物事がより明確になり、はるかに簡単になります。集約境界で。

Customer は注文のリストを含まない別の集計であり、 Order は注文明細のリストを含む集計である必要があると思います。顧客の注文ごとに操作を実行する必要がある場合は、 orderRepository.GetOrdersForCustomer(customerID); を使用します。変更を加えてから orderRespository.Save(order); を使用します。

4

3 に答える 3

2

いくつかコメントがあります:

割り当てロジックを分離することは正しいことです

割り当てロジックを ProjectService や EmployeeService などのサービス クラスに移動して、ドメイン モデルをロジックから解放することを検討してください。

割り当てを操作するために、新しい AllocationService クラスを追加することを検討してください。

public void Allocate(Project project, Role role, Employee employee, int percentage)
{
      // Fetch allocation from allocation repository
      var allocations = _allocationRepository.GetAllocations(project.Id);

      // project allocation logic
      if (!_projectService.Allocate(Project, Role, int percentage))
      {
          // throw exception
      }

      // allocate to employee
      if(!_employeeService.Allocate(employee, role, percentage))
      {
          // throw exception
      }

      // create new allocation
      _allocationRepository.Add(new Allocation
            {
                ......
            });
}

割り当てリポジトリとサービスは、コンストラクターを介して注入できます。

public interface IAllocationRepository
{
       IEnumerable<Allocation> GetAllocationsByProject(Project project);

       IEnumerable<Allocation> GetAllocationsByEmployee(Employee employee);

       void Add(Allocation);
}

IAllocationRepository は EmployeeService と ProjectService にも注入できるため、割り当てのリストを渡す必要はありません。

于 2013-12-23T09:33:07.987 に答える
1

割り当てロジックは、Project と Employee の 2 つのクラスに分割されています。

割り当ての責任が分割され、単一責任の原則が破られるため、私はこれを行いません。Projectそれがどちらにも属していないことがわかった場合はEmployeeドメイン サービスがその役割を果たします。一般に、同じ集合体の一部を形成しないいくつかのエンティティを含む操作は、そのようなサービスに配置される候補です。

クラスのList<Allocation>プロパティとして追加するのではなく、パラメーターとして Allocate メソッドに渡されます...それは正しいアプローチList<Allocation>ですか、それともこれら 2 つのクラスにプロパティとして追加する必要がありますか?

私の答えはどちらでもありません。クラスにList<Allocation>のみ追加してください。Project

あなたが考える必要があるAllocationのは、あなたのドメインで本当に何を表しているかだと思います。プロジェクト集計の一部を形成するエンティティですか? エンティティではなく、値オブジェクトでさえありますか?

データベース関係があると、ドメインの視点が失われることがあります。この場合、Allocation テーブルには独自の ID すらありません。Project代わりに、Employeeとの間の関係だけを表しているようでRole、いくつかの属性があります。ドメイン モデルは永続性を考慮すべきではありませんが、これはAllocation実際に何を表しているかについてのヒントを与えている可能性があります。

私の観点からは、Allocationは のコンテキストでのみ意味をなすProjectので、それはその集合体の一部であるべきです。おそらく、その等価性は ID に基づいていないため、値オブジェクトでさえある可能性があります。Project最初の制限 (割り当て時に予算を超えないこと) が満たされることを保証する責任は、エンティティに属し、従業員の割り当て時に実行される場合があります。

トリッキーな制約は 2 番目の制約です:Employee複数の を通じて 100% を超えない割り当てProjectsです。この場合、リポジトリProjectsを介して、特定のEmployeeが割り当てられているものを取得する手段を提供することに関心があるかもしれません。また、おそらくドメイン サービスを介して、特定の の合計割り当てを提供するためにチェックする操作を提供することもできます。Project Employee

クラスのAllocateメソッドで実際にこのすべてのロジックを実行していることに注意してください。最初にすべてのスルーを取得してから、実際に名前を付けることができる取得したリストを渡します。このビジネス ロジックを保証するのは の責任であると感じるかもしれませんが、そのプロパティや動作とはほとんど関係がなく、メソッドまたはドメイン サービスの一部であるべきだと私は思います。責任が混在していること。ProjectAllocationsGetAllocationsForEmployeeEmployee.AllocateCanBeAllocatedEmployeeProject.Allocate

最後に、以前のコメントで混乱が生じた場合に備えて、モデル クラス内にロジックを配置しても問題はありません。これは、実際にはドメイン モデリング全体の基本的な部分です。Martin Fowler による AnemicDomainModelの投稿は、これに関する良い洞察を提供します。

于 2014-01-02T11:43:51.013 に答える
1

ビジネス ルールは、既存の割り当てにも関連しています。Allocation を Aggregate にして、その Factory でビジネス ルールをラップするのはどうですか? お気に入り:

public Allocation Allocate(Project project, Role newRole, int newPercentage, Employee newEmployee)
{
     List<Allocation> existingAllocationsInProject = allocationRepository.findBy(project);
     //validate project rule
     List<Allocation> existingAllocationsInEmployee = allocationRepository.findBy(newEmployee);
     //validate employee rule
}

したがって、この場合、既存の割り当てを見つける方法について心配する必要はありません。また、ルールの検証は、仕様パターンを使用してさらにリファクタリングできます。

于 2013-12-23T09:28:15.340 に答える