这是依赖注入的正确用法吗?

时间:2011-07-04 09:50:12

标签: java design-patterns dependency-injection

此问题与此处的问题相关:configurable dependencies with easy to mock out default implementations

我的目标是按照DI模式设计小型库。拥有以下代码是DI的正确用法吗?

ValuesConfiguration只是Map的包装器。它是一种Value Object,它是由客户端在运行时创建的,因此不可能使用依赖注入。以前的版本(在相关问题中)将此配置作为构造函数参数,但它似乎不是“真正的”依赖。

public class Parser {

    private ValuesConfiguration configuration;
    private ValuesProvider valuesProvider;
    private ValuesMapper valuesMapper;

    public Parser() {}

    public Result parse(String parameterName) {
        initDefaults();           
        List<Values> values = valuesProvider.getValues(parameterName);
        ...
        return valuesMapper.transformValues(values, configuration);
    }

    private void initDefaults() {
        if(valuesProvider == null) {
            valuesProvider = DefaultsFactory.getDefaultValuesProvider();
        }
    }

    public void setConfiguration(ValuesConfiguration configuration) {
        this.valuesConfiguration = configuration;
    }

    public void setValuesProvider(ValuesProvider provider) {
        this.valuesProvider = provider;
    }

    ...

}

将配置作为parse()方法附加参数不是更好吗?

4 个答案:

答案 0 :(得分:3)

依赖注入的替代方法是让组件发现自己的依赖关系。在我看来,你已经使用了后来的模型。

如果您使用了依赖注入,那么您只需传递其所需的值,而不再传递它。即,不提取所有依赖关系。该组件不需要知道值的来源。

一个很大的提示是你的构造函数不带任何值,你的setter传递通用对象,一旦组件被正确初始化就不需要了。

如何更改它以使用DI。

public class Parser {

    private final ValuesProvider valuesProvider;
    private final ValuesMapper valuesMapper;
    private final ValuesConfiguration configuratrion;

    // all values injected.
    public Parser(ValuesProvider valuesProvider, ValuesMapper valuesMapper, ValuesConfiguration configuratrion) {
        this.valuesProvider = valuesProvider;
        this.valuesMapper = valuesMapper;
        this.configuratrion = configuratrion;
    }

    public Result parse(String parameterName) {
        List<Values> values = valuesProvider.getValues(parameterName);
        ...
        return valuesMapper.transformValues(values, configuration);
    }
 }

答案 1 :(得分:2)

我不会将工厂与DI结合起来。这只是令人困惑。例如,这里我们使用依赖注入:

public void setValuesProvider(ValuesProvider provider) {
    this.valuesProvider = provider;
}

但是哦等等,我们在这里使用工厂:

private void initDefaults() {
    if(valuesProvider == null) {
        valuesProvider = DefaultsFactory.getDefaultValuesProvider();
    }
}

也许我只是比大多数人慢,但对我来说,看起来精神分裂。如果要使用DI,请使用DI。设置一个特定的(命名的)默认提供程序并像这样调用它:

setValuesProvider(myDefaultProvider)

请注意,在这种情况下,您必须仔细记录它。或者另一种方法是使用一些聪明的继承(或者可能通过静态?)来将ANY ValuesProvider恢复到默认状态:

setValuesProvider(myProvider.defaultState())

后者对我来说最有意义。这里的想法需要是每当你想要使用Parser时,必须提供ValuesProvider。因此,我很可能会通过Parser()构造函数使用DI。

答案 2 :(得分:0)

DI并不总是合适的。使用DI工厂并不排除在所有情况下调用new。你的似乎就是其中之一。

答案 3 :(得分:0)

我喜欢使用默认值:

public Parser(ValuesMapper valuesMapper, ValuesConfiguration configuratrion) {
    this(DefaultsFactory.getDefaultValuesProvider(), valuesMapper, configuratrion);
}

// all values injected.
public Parser(ValuesProvider valuesProvider, ValuesMapper valuesMapper, ValuesConfiguration configuratrion) {
    this.valuesProvider = valuesProvider;
    this.valuesMapper = valuesMapper;
    this.configuratrion = configuratrion;
}