我正在研究一种参数值解析器库。我想将Parser定义如下:
public class Parser {
private ValuesConfiguration configuration;
private ValuesProvider valuesProvider;
private ValuesMapper valuesMapper;
public Parser(ValuesConfiguration configuration) {
this.configuration = configuration;
}
public Result parse(String parameterName) {
List<Values> values = valuesProvider.getValues(parameterName);
// do other stuff on values
// ...
return valuesMapper.transformValues(values, configuration);
}
}
我希望这个库客户端不知道ValuesProvider和ValuesMapper默认实现并使用它像
Result result = new Parser(myConfig).parse("sampleParam");
尽管必要时可以设置自己的实现。我想知道如何以及在何处启动这些默认实现,并且仍然允许客户端根据需要设置自己的实现。我不想坚持
new DefaultValuesProvider()
等。在构造函数中,因为默认实现将例如访问文件系统,因此很难测试(模拟它们)。我知道我可以使用setter(比如在DI中)但是默认情况呢?
编辑: 在你的所有答案之后,我想这里最好让setter允许客户提供他们自己的ValuesProvider和ValuesMapper实现。但是如何创建默认实现?我想将实例化与逻辑解耦,所以我不想在这里使用新的DefaultValueProvider()。工厂模式适用于此处吗?如果是这样,我应该如何以及在哪里使用它?
答案 0 :(得分:2)
怎么样:
public void setValuesProvider(ValuesProvider valuesProvider) {
this.valuesProvider = valuesProvider;
}
public Result parse(String parameterName) {
if (valuesProvider == null) {
valuesProvider = new DefaultValuesProvider();
}
List<Values> values = valuesProvider.getValues(parameterName);
// do other stuff on values
// ...
return valuesMapper.transformValues(values, configuration);
}
Mark指出,构造函数注入可能是更好的方法。这看起来如下:
public Parser(ValuesConfiguration configuration) {
this(configuation, new DefaultValuesProvider());
}
public Parser(ValuesConfiguration configuration, ValuesProvider valuesProvider) {
this.configuration = configuration;
this.valuesProvider = valuesProvider;
}
public Result parse(String parameterName) {
List<Values> values = valuesProvider.getValues(parameterName);
// do other stuff on values
// ...
return valuesMapper.transformValues(values, configuration);
}
我也同意他对优势的总结:
这将使您能够使依赖关系最终/只读。 Property Injection提供了关于不变量的非常弱的保证 - 例如你可以继续改变对同一个实例的依赖性,这可能不是你想要的。
然而,也有缺点:
因此,我的建议是使用setter注入,如果有必要阻止重新分配依赖项,请执行以下操作:
public void setValuesProvider(ValuesProvider valuesProvider) {
if (this.valuesProvider != null) {
throw new IllegalStateException("Dependency already set");
}
this.valuesProvider = valuesProvider;
}
答案 1 :(得分:0)
使用Google Guice或类似的依赖注入框架:
http://code.google.com/p/google-guice/
它非常适合您的需求。您可以配置几个模块,描述将为特定接口实例化的实现。例如,您可以拥有ProductionModule和UnitTestModule。