我正在尝试解决依赖于我正在调用的操作中的参数值的依赖关系。
我有这个 WCF 服务
public class InformationService : IInformationService
{
private readonly IValueProvider _valueProvider;
public InformationService(IValueProvider valueProvider)
{
_valueProvider= valueProvider;
}
public CompanyReportResponse CompanyReport(string option)
{
_valueProvider.Execute(option);
}
}
我还在我的容器中为我的价值提供者注册了两种具体类型。
Registry.For<IValueProvider>().Add<ValueProvider1>().Named("No1");
Registry.For<IValueProvider>().Add<ValueProvider2>().Named("No2");
是否可以根据选项的值以某种方式使用不同的值提供程序?
即,当选项"value1"
时,_valueProvider
将使用具体类型ValueProvider1
,当选项"value2
"时,_valueProvider
将使用具体类型ValueProvider2
。
+1 表示@filpen的答案。我喜欢添加第三个选项。您可以引入委托给正确实现的代理,而不是注入工厂或执行基于上下文的注入:
public SwitchingValueProviderProxy: IValueProvider
{
private readonly ValueProvider1 provider1;
private readonly ValueProvider2 provider2;
public SwitchingValueProviderProxy(
ValueProvider1 provider1,
ValueProvider2 provider2)
{
this.provider1 = provider1;
this.provider2 = provider2;
}
void IValueProvider.Execute(option option)
{
this.GetProvider(option).Execute(option);
}
private IValueProvider GetProvider(string option)
{
// custom instance logic here
if (option.EndsWith("1"))
return this.provider1;
if (option.EndsWith("2"))
return this.provider2;
throw InvalidOperationException();
}
}
这有几个明显的优势。首先,这完全隐藏了工厂和确定从客户端执行哪个提供程序的逻辑。客户端现在仅依赖于IValueProvider
接口。接下来,配置现在变得非常干净:
Registry.For<IValueProvider>()
.Add<SwitchingValueProviderProxy>();
就是这样。如果你这样做,你仍然可以将选择逻辑提取到IValueProviderFactory
中并将其注入到SwitchingValueProviderProxy
中,这使这个类保持简单和集中,并且仍然使应用程序的其余部分对工厂一无所知。
我看到至少 2 个不同的选项。
如果该方法仅使用ValueProvider
,则可以考虑方法注入。由于在传递option
参数的那一刻,您已经知道将使用哪一个参数,因此您可以为 IValueProvider 提供实现以用作附加参数。
public CompanyReportResponse CompanyReport(string option, IValueProvider provider)
{
_provider.Execute(option);
}
第二个选项是定义一个工厂来构建你的 ValueProvider,并通过构造函数注入注入这个工厂。工厂将有一个方法,用于根据option
参数实例化正确的 ValueProvider。
public interface IValueProviderFactory
{
IValueProvider CreateProvider(string option);
}
public class ValueProviderFactory : IValueProviderFactory
{
public IValueProvider CreateProvider(string option)
{
// Insert custom instantiation logic here:
// if option == "value1" return ValueProvider1 and so on
}
}
public class InformationService : IInformationService
{
private readonly IValueProviderFactory _valueProviderFactory;
public InformationService(IValueProviderFactory valueProviderFactory)
{
_valueProviderFactory = valueProviderFactory;
}
public CompanyReportResponse CompanyReport(string option)
{
var valueProvider = _valueProviderFactory.CreateProvider(option);
valueProvider.Execute(option);
}
}