顾名思义,设计服务层时的最佳实践是什么?我确实知道服务层应始终返回DTO,以便将域(实体)对象保留在服务层内。但是,控制器对服务层的输入应该是什么?
我在下面提出了三个建议:
方法1:
在这种方法中,域对象(项)保留在服务层中。
class Controller
{
@Autowired
private ItemService service;
public ItemDTO createItem(IntemDTO dto)
{
// service layer returns a DTO object and accepts a DTO object
return service.createItem(dto);
}
}
方法2:
这是服务层接收自定义请求对象的地方。我已经在AWS Java SDK和Google Cloud Java API中广泛地看到了这种模式
class Controller
{
@Autowired
private ItemService service;
public ItemDTO createItem(CreateItemRequest request)
{
// service layer returns a DTO object and accepts a custom request object
return service.createItem(request);
}
}
方法3:
服务层接受DTO并返回域对象。我不喜欢这种方法。但是它已在我的工作场所广泛使用。
class Controller
{
@Autowired
private ItemService service;
public ItemDTO createItem(CreateItemRequest request)
{
// service layer returns a DTO object and accepts a DTO object
Item item = service.createItem(request);
return ItemDTO.fromEntity(item);
}
}
如果以上三种方法都不正确或不是最佳方法,请就最佳实践向我提出建议。
最佳答案
我来自C#
背景,但是这里的概念仍然相同。
在这种情况下,我们必须将参数/状态从应用程序层传递到服务层,然后从服务层返回结果,我倾向于遵循关注点分离。服务层无需了解应用程序层/控制器的Request
参数。同样,从服务层返回的信息不应与从控制器返回的信息相结合。这些是不同的层,不同的需求,不同的关注点。我们应避免紧密耦合。
对于上面的示例,我将执行以下操作:
class Controller
{
@Autowired
private ItemService service;
public ItemResponse createItem(CreateItemRequest request)
{
var creatItemDto = GetDTo(request);
var itemDto = service.createItem(createItemDto);
return GetItemResponse(itemDto);
}
}
由于您现在需要编写其他代码来转换不同的对象,因此这可能需要做更多的工作。但是,这给您很大的灵活性,并使代码更易于维护。例如:与
CreateItemDto
相比,CreateItemRequest
可能具有其他/计算字段。在这种情况下,您无需在Request
对象中公开那些字段。您只将Data Contract
暴露给客户端,仅此而已。同样,您只将相关字段返回给客户端,而不是将您从服务层返回的内容返回给客户端。如果要避免在
Dto
和Request
之间相互映射objects
C#具有类似AutoMapper
的库。在Java世界中,我确定应该有一个等效项。可能ModelMapper可以帮助您。