此问题与此处的问题相关: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()方法附加参数不是更好吗?
答案 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;
}