顾名思义,设计服务层时的最佳实践是什么?我确实知道服务层应始终返回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暴露给客户端,仅此而已。同样,您只将相关字段返回给客户端,而不是将您从服务层返回的内容返回给客户端。

如果要避免在DtoRequest之间相互映射objects C#具有类似AutoMapper的库。在Java世界中,我确定应该有一个等效项。可能ModelMapper可以帮助您。

10-07 18:04