单例方法控制器中构建器的陷阱?

时间:2016-10-13 15:02:03

标签: java design-patterns dependency-injection controller singleton

假设我在Spring中有控制器RequestController,标记为Singleton。在该控制器内部有一个使用依赖注入注入的构建器。此课程的主要目标是接收请求并构建响应。

@Singleton
class RequestController {
    private ResponseBuilder responseBuilder;

    private RequestController(ResponseBuilder responseBuilder){
        this.responseBuilder=responseBuilder;
    }

    public Response getResponse(Request request) {
        return responseBuilder.getRequest(request).build();
    }
}

我的问题:

这段代码隐藏了什么样的陷阱?当我们尝试在普通弹簧应用中使用它时会出现什么问题。 @Singleton只是一个信息,每个应用程序只会创建一次此类。 我知道构建器应该是线程安全的,因为它将负责处理多个请求。但这里还有其他危险吗?

2 个答案:

答案 0 :(得分:0)

在提出问题之前,有一件事需要提及。您已使用RequestController将您的班级@Singleton声明为 Singleton 。如果你的类是单例,你应该确保它是不可变的,所以创建后没有状态改变。所以我认为这是一个无国籍的阶级。因此,您不需要拥有私有构造函数,这看起来相当混乱。相反,你可以使用,

@Inject
private RequestController(ResponseBuilder responseBuilder){
        this.responseBuilder=responseBuilder;
}

请注意,如果您保持良好的设计,ResponseBuilder课程应该是可注射的课程。 RequestController类只能通过注入来调用。

回到你的问题,我认为你几乎没有问题。我们应该对what our real problem is?而非what patterns we could drag and drop into our code?

非常谨慎

制作一个控制器,一个Singleton非常好。但我发现没有必要使用Builder模式到您的ResponseBuilder(您也可以更改名称)。如果您的课程相当简单并且操作数量有限(设计良好的标志),那么您的生命周期中永远不需要构建器模式。这更像是我们试图用斧头撕纸。你为什么不赤手空拳?

我们应该只在出于某种原因必须制作相当大的范围类的情况下使用构建器。您可以在Hamcrest中使用Builder模式的一个很好的例子。它是由Google开发的用于Java测试的assertion工具。他们使用了一些类的构建器模式,只为通过从单个对象提供多个任务列表而使用它的程序员更轻松地生活。

答案 1 :(得分:0)

感谢回复...我知道这段代码有什么问题...当然我应该在ResponseBuilder上使用注入。但是经典构建器模式有一个状态所以在无状态控制器中我们使用ResponseBuilder提供的statefull类。因此,如果它不是线程安全的话,它会自动构建它会导致并发问题(竞争条件)。每当多个线程尝试访问构建器字段时,它们就可以获得不同的状态(因为构建器不是线程安全的)。因此,当我们尝试使构建器线程安全时,它将起作用但会出现新问题。由于我们的构建器变得线程安全,因此只有一个线程可以使用它,这可以导致我们为请求引导bootleneck(多个请求/线程使用我们的方法,但是它们将被构建器阻塞,这是线程安全的)。如果我的想法很好,那就给我一个大喊大叫:)