题
我试图理解贫血领域模型以及为什么它们被认为是反模式。
这是一个现实世界的例子。
我有一个 Employee 类,它有大量的属性 - 姓名、性别、用户名等
public class Employee
{
public string Name { get; set; }
public string Gender { get; set; }
public string Username { get; set; }
// Etc.. mostly getters and setters
}
接下来,我们有一个系统,该系统涉及在销售人员之间均匀轮流来电和网站查询(称为“潜在客户”)。该系统非常复杂,因为它涉及循环查询、检查假期、员工偏好等。所以这个系统目前被分成一个服务:员工领导轮换服务。
public class EmployeeLeadRotationService : IEmployeeLeadRotationService
{
private IEmployeeRepository _employeeRepository;
// ...plus lots of other injected repositories and services
public void SelectEmployee(ILead lead)
{
// Etc. lots of complex logic
}
}
然后在我们网站查询表格的背面有这样的代码:
public void SubmitForm()
{
var lead = CreateLeadFromFormInput();
var selectedEmployee = Kernel.Get<IEmployeeLeadRotationService>()
.SelectEmployee(lead);
Response.Write(employee.Name + " will handle your enquiry. Thanks.");
}
我并没有真正遇到这种方法的很多问题,但据说这是我应该尖叫的事情,因为它是一个 贫血域模型.
但对我来说,不清楚领先轮换服务的逻辑应该去哪里。它应该领先吗?它应该放在员工身上吗?
轮换服务所需的所有注入存储库等怎么样?考虑到大多数时候我们在与员工打交道时不需要任何这些存储库,那么如何将它们注入到员工中?
解决方案
在此情况下,这并不构成贫血域模型。贫血域模型是具体地约验证和变换对象。所以这方面的一个例子是,如果外部函数实际改变雇员的状态或更新它们的细节。
什么是在这种情况下发生的是你正在服用的所有员工,并作出选择基于他们的信息的其中之一。这是罚款,有一个单独的对象,检他人并作出决定关于什么发现。它不是确定有一个用于从一个状态的对象过渡到另一个对象。
贫血域模型中的情况的一个例子将是具有外部方法
updateHours(Employee emp) // updates the working hours for the employee
这需要一个Employee对象和更新其工作时间为一周,确保如果时间超过一定的极限标志被提高。这里的问题是,如果你只有Employee对象,那么你有没有对如何正确约束范围内修改其小时知识。在这种情况下,对付它的方法是将移动updateHours方法为Employee类。这是贫血领域模型反图案的关键所在。
其他提示
我觉得你的设计是在这里很好。如你所知,贫血域模型反模式是针对避免在域中的对象编码的任何行为趋势的反弹。但反过来说,这并不意味着的有关的域对象的所有的行为必须由该对象进行封装。
作为一个经验法则,行为被intrinsicly绑定到域对象,并且在那一个域对象实例而言完全定义可以被包括在域对象。否则,保持职责明确,最好把它在外部的合作者/服务就像你做了。
这一切都在你的头上 - 考虑旋转服务是域模型的一部分,问题溶解
旋转需要保持对多雇员的信息,因此它属于既不铅,也没有任何单一的雇员对象。它的确值得是域对象本身。
只要重命名 “RotationService” 以类似 “Organization.UserSupportDepartment” 使得它显而易见的。
如果您的领域模型仅包含角色和事物,而不包含作为行为的活动,那么它是贫乏的。然而,我谈论的是关于 模型 不是一个 目的. 。我在另一个答案中谈到了它们之间的区别...... https://stackoverflow.com/a/31780937/116442
从你的问题来看,你打破了我的前两个领域分析建模规则:-
- 建模为(记录的)活动的行为是领域模型的核心。首先添加它们。
- 将领域活动建模为类,而不是方法。
我将向模型添加一个活动“查询”。有了它,模型就有了行为,并且可以组合并作为一组对象工作,而无需外部控制器或脚本。