状态依赖性和线程安全性

我有Struts 1动作类(动作是struts 1中的设计单例),需要收集一些数据,然后将它们组合成单个响应。 我想将所有的响应生成逻辑提取到单独的类中

ResponseBuilder

通常情况下,我会把ResponseBuilder作为一个字段并为其设置(例如,用于测试)。 我的响应生成器如下所示

class JsonResponseBuilder implements ResponseBuilder {
    public void addElement(String key, Object value) {
        ...
    }

    public String buildResponse() {
        // build response from data collected
    }
}

有了这样的实现,我不能这样做,因为线程安全问题在这里。

我该如何改变这种设计才行? 这里的工厂模式是否适用? 我的意思是使用

ResponseBuilderFactory

作为依赖关系并且这样调用它:

ResponseBuilder builder = factory.getBuilder();
builder.addElement(...);
...
String response = builder.build();

从设计和可测试性的角度来看是否可行? 如果没关系。 如何为此编写测试代码? 模拟工厂? 模拟建造者?


工厂会工作。 你基本上正在用工厂做一种依赖注入的形式。 当你实例化或初始化你的动作时,你可以设置工厂:

public void setResponseFactory(ResponseBuilderFactory factory) {
    this.responseFactory = factory;
}

并且在工厂中,只需在需要时返回JsonResponseBuilder的新实例。 确保你不将JsonResponseBuilder的实例作为实例变量存储在你的动作中; 它必须保持在您正在使用的方法的本地,或作为方法参数传递。

至于测试,用一个模拟工厂替换工厂变得容易,该工厂返回一个模拟的ResponseBuilder。 有许多库可以做到这一点,例如Mockito或JMock。 它们都能很好地与JUnit和TestNG配合使用。

编辑:

您需要将ResponseBuilderFactory作为接口,如下所示:

public interface ResponseBuilderFactory {
    public ResponseBuilder getResponseBuilder();
}

当你进行测试时,只需创建一个返回ResponseBuilder模拟的类:

@Test
public void testMyAction() throws Exception {
    ResponseBuilderFactory mockFactory = new ResponseBuilderFactory() {
        public ResponseBuilder getResponseBuilder() {
            ResponseBuilder builder = context.mock(ResponseBuilder.class);
            // set up mock behaviour
            return builder;
        }
    }
}

所以你不注射一个模拟工厂,只是一个返回模拟的工厂。

另请参阅依赖注入VS工厂模式。

编辑2:

如果你可以设法重新编写你的JsonResponseBuilder以便它不保持状态,那么你可以避免整个工厂混乱在一起,只使用你的原始方法。 不保持状态的对象本质上是线程安全的。


只需在您的Action Service方法中实例化ResponseBuilder。 这样它将是一个局部变量(而不是一个单独的类成员),每个线程都将有一个独特的ResponseBuilder新实例。

您可以单独测试ResponseBuilder,并且您也可以像其他任何操作一样正常测试您的操作(如果需要,可以模拟ResponseBuilder)。

使用工厂模式构建ResponseBuilder是另一回事,与您的问题imo无关。 如果实例化ResponseBuilders是昂贵的并且它们是可重用的,那么您可能希望使用ResponseBuilders池。


在Action中使ResponseBuilder成为变量的那一瞬间,它就在所有请求中共享。 这意味着你必须同步它,以确保它的可变状态(如果有的话)是线程安全的。

另一种方法是在调用每个动作的方法内部创建一个新的ResponseBuilder。 您以这种方式为每个请求创建一个实例。

链接地址: http://www.djcxy.com/p/77759.html

上一篇: stateful dependency and thread safety

下一篇: Dependency Injection Container