2

我有一个具有以下业务规则的项目分配域

  1. 当一名新员工被分配到一个项目时,总支出不应超过预算金额。
  2. 对于员工,总分配百分比不应超过 100%

我已经创建了如下所示的实体C#

问题

Allocate逻辑分为两个类 - Project 和 Employee ..作为参数传递给 Allocate 方法,而不是作为类的List<Allocation>属性添加......这是正确的方法还是我需要List<Allocation>在这两个类中添加作为属性?

笔记:

数据库

在此处输入图像描述

权利

在此处输入图像描述

代码

项目

 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

业务规则也与现有分配相关。让 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
}

所以在这种情况下,我们不必担心如何找到现有的Allocations。并且可以使用规范模式进一步重构规则验证。

于 2013-12-23T09:28:15.340 回答
1

Allocate 逻辑分为两个类——Project 和 Employee..

我不会这样做,因为它拆分了分配责任,从而打破了单一责任原则。如果您发现它既不属于也不属于ProjectEmployee那么域服务可能会完成这项工作。通常,涉及不构成同一聚合的一部分的多个实体的操作是位于此类服务中的候选对象。

List<Allocation>作为参数传递给 Allocate 方法,而不是作为类的属性添加......这是正确的方法还是我需要List<Allocation>在这两个类中添加作为属性?

我的答案不是那些:List<Allocation>只添加到你的Project班级。

我认为您需要考虑的是Allocation在您的领域中真正代表什么。它是构成项目聚合一部分的实体吗?它甚至可能是一个值对象而不是一个实体?

有时,当我有数据库关系时,我发现自己失去了对领域的看法。在这种情况下,我看到分配表甚至没有自己的 id;相反,它似乎只代表 和 之间的关系ProjectEmployeeRole具有几个属性。尽管域模型不应该关心持久性,但这可能会给出一些关于Allocation真正代表什么的提示。

从我的角度来看, aAllocation仅在 a 的上下文中才有意义,Project因此它应该是该聚合的一部分。可以说,它的相等性不是基于身份,因此,它甚至可能是一个值对象。确保满足第一个限制(分配时不超过预算)的责任属于Project实体,并且可以在员工分配时执行。

棘手的约束是第二个:Employee通过几个Projects. 在这种情况下,您可能有兴趣提供获取分配Projects给定Employee对象的方法,可能是通过您的Project 存储库。您还可以提供一个操作来检查以提供给定的总分配Employee,可能通过域服务

请注意,您实际上是在Allocate您的类的方法中执行所有这些逻辑Project:首先您获得所有Allocations通过GetAllocationsForEmployee,然后将检索到的列表传递给Employee.Allocate实际上可以命名的列表CanBeAllocated。你可能觉得确保这个业务逻辑是责任,但我认为它与它的属性和行为都无关,因此,如果你一直觉得Employee它应该是Project.Allocate方法或域服务的一部分有混合的责任。

最后一点,如果前面的评论有一些混淆,把逻辑放在你的模型类中没有错,它实际上是整个领域建模的一个基本部分!Martin Fowler的AnemicDomainModel 帖子对此提供了一些很好的见解。

于 2014-01-02T11:43:51.013 回答