我有一个包含以下业务规则的项目分配域
我创建了如下C#
中创建的实体。
问题
Allocate
逻辑分为两个类 - Project和Employee .. List<Allocation>
作为参数传递给Allocate方法,而不是作为类的属性添加......是否正确方法还是我需要在这两个类中添加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;
}
}
参考
以下来自Repository Pattern without an ORM
有什么行为要求客户拥有订单清单?当您更多地考虑域的行为(即在什么点需要什么数据)时,您可以根据用例对事物进行建模,事情变得更加清晰和简单,因为您只需更改跟踪一小组对象在总边界。
我怀疑客户应该是一个没有订单列表的单独聚合,订单应该是一个包含订单行列表的聚合。如果您需要对客户的每个订单执行操作,请使用orderRepository.GetOrdersForCustomer(customerID);进行更改然后使用orderRespository.Save(order);
答案 0 :(得分: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中,因此您无需传递分配列表。
答案 1 :(得分:1)
业务规则也与现有分配相关。如何使Allocation成为聚合并在其工厂中包装业务规则?像:
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
}
所以在这种情况下,我们不必担心如何找到现有的Allocllations。并且可以使用规范模式进一步重构规则valiation。
答案 2 :(得分:1)
Allocate逻辑分为两个类 - Project和Employee ..
我不会这样做,因为它分配了分配责任,从而违反了单一责任原则。如果您发现它既不属于Project
也不属于Employee
,那么domain service可能会完成此任务。一般而言,涉及多个不属于同一聚合的实体的操作是位于此类服务中的候选者。
List<Allocation>
作为参数传递给Allocate方法而不是作为类的属性添加...是正确的方法还是我需要在这两个类中添加List<Allocation>
作为属性?
我的回答不是那些:仅将List<Allocation>
添加到您的Project
课程。
我认为您需要考虑的是Allocation
在您的域中真正代表的含义。它是构成项目聚合的一部分的实体吗?它甚至可以是价值对象而不是实体吗?
当我有数据库关系时,有时我发现自己失去了对域的看法。在这种情况下,我看到Allocation表甚至没有自己的id;相反,它似乎只代表具有多个属性的Project
,Employee
和Role
之间的关系。虽然域模型不应该关注持久性,但这可能会提供一些关于Allocation
真正代表什么的提示。
从我的观点来看,Allocation
仅在Project
的上下文中有意义,因此它应该是该聚合的一部分。可以说,its equality is not based on identity因此,它甚至可能是一个价值对象。确保第一项限制 - 不超过分配预算 - 的责任属于Project
实体,可以在员工分配时执行。
棘手的约束是第二个:Employee
通过几个Projects
分配不超过100%。在这种情况下,您可能有兴趣提供方法来获取分配了给定Projects
的{{1}},可能通过您的Employee
存储库。您还可以提供检查操作,以便通过域名服务提供给定Project
的总分配。
请注意,您实际上是在Employee
课程的Allocate
方法中执行所有这些逻辑:首先,您获得Project
到Allocations
的全部内容然后通过检索到GetAllocationsForEmployee
的列表,该列表实际上可以命名为Employee.Allocate
。您可能认为CanBeAllocated
负责确保此业务逻辑,但我认为它与其属性及其行为无关,因此,它应该是{{1}的一部分。方法或域名服务,如果您一直认为存在混合责任。
最后要注意的是,如果先前的注释存在一些混淆,将逻辑放入模型类中是没有错的,它实际上是整个域建模的基本部分! AnemicDomainModel post by Martin Fowler提供了一些很好的见解。