4

我正在开发一个具有在域模型上运行的服务层的应用程序。在当前的设计中,我通过服务层向上传递域对象(例如,Employee在调用时返回域对象EmploymentService.getEmployee(),但要求对对象执行的操作通过服务进行(例如EmploymentService.transferEmployee( int employeeId, int newLocationId)。(顺便说一下,示例是人为的)。

这对我来说有点不对劲。一,它看起来像过程编程。第二,域对象具有诸如Employee.setLocationId客户端可以调用的设置器,当然不会将员工转移到新位置,因为协调假设转移员工所需的不同系统的所有复杂操作都在服务层中。

如果我可以对客户端隐藏设置器,我会感觉更好,但是不同包中的 ServiceLayer 和 DAO 都需要能够访问域对象的设置器。

这种事情可以吗,还是有更好的方法?(此外,任何具有底层域模型的服务层的真实示例都将受到欢迎!)

另外,我已经阅读了贫血域模型反模式,我认为我没有落入那个陷阱,但我并不完全确定!

4

3 回答 3

3

首先,客户端调用 Employee.Transfer() 的问题是您实际上并不想要的:我喜欢只从我的服务层返回 DTO。这些 DTO 包含数据但没有方法。这解决了客户端调用 Employee.Transfer() 的问题。

接下来是在EmploymentService.transferEmployee() 中拥有所有代码的问题。你说它感觉不对,因为它看起来像程序化编程。解决方案是在您放入 Service 的逻辑和放入 Domain 对象的逻辑之间找到一个很好的组合。例如:

域对象:

  • 检查它是否没有被删除
  • 检查它是否不在该位置
  • 等等

服务层可以:

  • 加载员工
  • 致电 Employee.Transfer
  • 向员工发送电子邮件
  • 向位置经理发送电子邮件
  • 等等

我可能会在此代码中使用 Location Domain 对象:

public class Location
{
   public void AddEmployee(Employee emp)
   {
      if(!IsFull)
         Employees.Add(emp);
   }

   public void RemoveEmployee(Employee emp)
   {
      Employees.Remove(emp);
      If(Employees.Count < 100)
         IsFull = false;
   }
}
于 2012-04-08T12:18:44.110 回答
2

首先,虽然你说你的例子是人为的,但我想说这EmploymentService.transferEmployee(int employeeId, int newLocationId)有点奇怪。通常你会将一个转移Employee到一个Location。在 Java 代码中处理 id 是不寻常的。大多数 ORM 都会为您处理。

至于你的问题,我会把转移 an 的逻辑放在Employee里面Employee。这样一来,如果Employee.setLocation(Location)没有进行适当的更改,就不可能有人打电话。这比试图从某些对象中隐藏二传手要好得多。

正如贫血领域模型的维基百科页面中所述,该模式描述了一个系统,其中领域转换由单独的对象控制。我个人认为转移anEmployee确实是一种转换,这种转换的逻辑可以而且应该在Domain层。当然,这些问题总是有点口味问题,所以你可能会有不同的想法。

我发现 Martin Fowler关于这个问题的原始文章是一个很好的论据,可以让您的域对象能够自我转换。

于 2012-04-07T00:16:54.270 回答
1

对客户端隐藏 setter 的一种常用方法是将客户端需要的所有 getter 封装在IEmployee接口中,并将服务 API 编码到该接口。这样,setter 对客户端隐藏,但对于需要它们的服务和 DAO 仍然存在。

于 2012-04-06T21:51:20.653 回答