我正在开发一个具有在域模型上运行的服务层的应用程序。在当前设计中,我将域对象传递到服务层(例如,在调用Employee
时返回EmploymentService.getEmployee()
域对象,但要求对对象执行的操作通过服务(例如{{ 1}}。(顺便说一下,例子是人为的。)
这对我来说有点不对劲。一,它似乎是程序式编程。二,域对象具有像EmploymentService.transferEmployee( int employeeId, int newLocationId)
这样的设置者,客户端可以调用这些设置器当然不会将员工转移到新的位置,因为协调不同系统所需的所有复杂操作都是假设转移员工所在的服务层。
如果我可以从客户端隐藏setter,我会感觉更好,但不同包中的ServiceLayer和DAO都需要能够访问域对象的setter。
这种事情好吗,还是有更好的方法? (此外,欢迎使用基础域模型的任何实际服务层示例!)
另外,我已经阅读了Anemic Domain Model的反模式,我不会认为我陷入了这个陷阱,但我并不完全确定!
答案 0 :(得分:3)
首先,客户端调用您实际上并不想要的Employee.Transfer()的问题: 我喜欢只从我的服务层返回DTO。这些DTO包含数据而没有方法。这解决了客户端调用Employee.Transfer()。
的问题接下来,在EmploymentService.transferEmployee()中包含所有代码的问题。你说它感觉不对,因为它看起来像程序编程。解决方案是在您放入服务的逻辑和放入Domain对象的逻辑之间找到一个很好的组合。例如:
域对象:
服务层确实:
我可能会在此代码中使用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;
}
}
答案 1 :(得分:2)
首先,虽然你说你的例子是人为的,但我想说EmploymentService.transferEmployee(int employeeId, int newLocationId)
有点奇怪。通常您会将Employee
转移到Location
。必须在Java代码中处理id是不常见的。大多数ORM都会为您处理。
至于你的问题,我会在Employee
本身提出转移Employee
的逻辑。这样,如果没有进行适当的更改,有人就无法致电Employee.setLocation(Location)
。这比通过箍试图隐藏某些物体的设置者要好得多。
如Anemic Domain Model的维基百科页面所述,该模式描述了一个系统,其中域转换由不同的对象控制。我个人认为转移Employee
确实是一种转变,并且这种转换的逻辑可以而且应该在域层中。当然,这些问题总是有些问题,所以你可能会有不同的想法。
我发现Martin Fowler的original article on the issue是让你的Domain对象能够改变自己的非常好的论据。
答案 2 :(得分:1)
从客户端隐藏setter的一种常用方法是在IEmployee
接口中封装客户端需要的所有getter,并将服务API编码到该接口。这样,setter对客户端是隐藏的,但仍然存在需要它们的服务和DAO。