gpt4 book ai didi

java - 可配置的依赖关系,易于模拟默认实现

转载 作者:行者123 更新时间:2023-12-02 08:15:19 25 4
gpt4 key购买 nike

我正在开发一种参数值解析器库。我想要一个解析器定义如下:

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 实现。但如何创建默认实现呢?我想将实例化与逻辑分离,所以我不想在这里使用 new DefaultValueProvider() 。工厂模式在这里适用吗?如果是这样,我应该如何以及在哪里使用它?

最佳答案

怎么样:

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 指出的那样,构造函数注入(inject)可能是更好的方法。看起来如下:

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);
}

我也同意他总结的优点:

This would enable you to make the dependency final/readonly. Property Injection provides quite weak guarantees about invariants - e.g. you could keep changing the dependency on the same instance, and that's probably not what you want.

但是,也有缺点:

  1. 构造函数的数量与可选参数的数量呈指数关系,导致参数的大量委托(delegate)和重复的 JavaDoc。因此,如果可选依赖项很少,我只会使用构造函数注入(inject)。你有 2,这大约是我对这种事情的疼痛阈值。
  2. 构造函数注入(inject)对子类化不太友好,因为子类构造函数必须重新声明父类(super class)依赖项。在您的情况下,希望公开所有配置选项的子类将需要 4 个构造函数……如果它添加一个可选参数,最好不要使用构造函数注入(inject),因为这将需要另外 4 个构造函数。

因此,我的建议是使用 setter 注入(inject),如果有必要防止重新分配依赖项,请执行以下操作:

public void setValuesProvider(ValuesProvider valuesProvider) {
if (this.valuesProvider != null) {
throw new IllegalStateException("Dependency already set");
}
this.valuesProvider = valuesProvider;
}

关于java - 可配置的依赖关系,易于模拟默认实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6553948/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com