在这种情况下如何使用 Castle Windsor 类型的工厂?
How to use Castle Windsor typed factory in this case?
简单的 DI 示例:
public interface INumberToWordConverter
{
string ConvertNumber(int number);
}
public interface IOutputManager
{
void Write<T>(string who, T what);
}
public interface INumberProvider
{
int GenerateNumber();
}
public class PlayWithDI
{
private IOutputManager _outputManagerService;
private INumberProvider _numberProviderService;
private INumberToWordConverter _numberToWordConverterService;
private PlayWithDI() { }
public PlayWithDI(
IOutputManager outputManagerService,
INumberProvider numberProviderService,
INumberToWordConverter numberToWordConverterService)
{
if (outputManagerService == null)
throw new ArgumentNullException(nameof(outputManagerService));
if (numberProviderService == null)
throw new ArgumentNullException(nameof(numberProviderService));
if (numberToWordConverterService == null)
throw new ArgumentNullException(nameof(numberToWordConverterService));
_outputManagerService = outputManagerService;
_numberProviderService = numberProviderService;
_numberToWordConverterService = numberToWordConverterService;
}
public void Execute()
{
int number = _numberProviderService.GenerateNumber();
string wordOfNumber = _numberToWordConverterService.ConvertNumber(number);
_outputManagerService.Write(nameof(PlayWithDI), wordOfNumber);
}
示例实现(只是 ctors):
// Implements INumberProvider
public RandomNumberProvider(
int min, int max,
IOutputManager outputManagerService)
{
...
}
// Implements INumberToWordConverter
public ItalianNumberToWordConverter(
IOutputManager outputManagerService)
{
...
}
// Implements IConsoleManager
public ConsoleOutputManager()
{
...
}
如果我知道 min
和 max
给了 RandomNumberProvider
,我会这样解决:
public void Install(
IWindsorContainer container,
IConfigurationStore store)
{
container.Register(
Component.For<PlayWithDI>());
container.Register(
Component.For<IOutputManager>()
.ImplementedBy<ConsoleOutputManager>());
container.Register(
Component.For<INumberProvider>()
.ImplementedBy<RandomNumberProvider>()
.DependsOn(
Dependency.OnValue("min", 2),
Dependency.OnValue("max", 20)));
container.Register(
Component.For<INumberToWordConverter>()
.ImplementedBy<ItalianNumberToWordConverter>());
}
...
container.Install(new DependenciesConfiguration1());
var testDI = container.Resolve<PlayWithDI>();
testDI.Execute();
当我想在运行时为 RandomNumberProvider
提供自定义参数时出现问题。
我看了一下TypedFactory
,但是这个例子我不是很懂,因为如果我先解析一个factory,那么PlayWithDi应该怎么解析呢?我应该将 INumberProviderFactory 而不是 INumberProvider 传递给它的构造函数吗?
在这种情况下,我想到了这样一个工厂:
public interface INumberProviderFactory
{
INumberProvider Create(
IOutputManager outputManager,
int min, int max);
}
当我再调用Create
时,我应该如何解析outputManager
呢?我很困惑。
The problem arises when I want to give custom parameters to RandomNumberProvider at runtime.
这就是你出错的地方。 Injecting runtime data into components during construction is ananti-pattern:
Don't inject runtime data into application components during construction; it causes ambiguity, complicates the composition root with an extra responsibility and makes it extraordinarily hard to verify the correctness of your DI configuration. [...] Let runtime data flow through the method calls of constructed object graphs.
换句话说,您的 RandomNumberProvider
应该接受 min
和 max
参数是 GenerateNumber
方法的输入参数。
简单的 DI 示例:
public interface INumberToWordConverter
{
string ConvertNumber(int number);
}
public interface IOutputManager
{
void Write<T>(string who, T what);
}
public interface INumberProvider
{
int GenerateNumber();
}
public class PlayWithDI
{
private IOutputManager _outputManagerService;
private INumberProvider _numberProviderService;
private INumberToWordConverter _numberToWordConverterService;
private PlayWithDI() { }
public PlayWithDI(
IOutputManager outputManagerService,
INumberProvider numberProviderService,
INumberToWordConverter numberToWordConverterService)
{
if (outputManagerService == null)
throw new ArgumentNullException(nameof(outputManagerService));
if (numberProviderService == null)
throw new ArgumentNullException(nameof(numberProviderService));
if (numberToWordConverterService == null)
throw new ArgumentNullException(nameof(numberToWordConverterService));
_outputManagerService = outputManagerService;
_numberProviderService = numberProviderService;
_numberToWordConverterService = numberToWordConverterService;
}
public void Execute()
{
int number = _numberProviderService.GenerateNumber();
string wordOfNumber = _numberToWordConverterService.ConvertNumber(number);
_outputManagerService.Write(nameof(PlayWithDI), wordOfNumber);
}
示例实现(只是 ctors):
// Implements INumberProvider
public RandomNumberProvider(
int min, int max,
IOutputManager outputManagerService)
{
...
}
// Implements INumberToWordConverter
public ItalianNumberToWordConverter(
IOutputManager outputManagerService)
{
...
}
// Implements IConsoleManager
public ConsoleOutputManager()
{
...
}
如果我知道 min
和 max
给了 RandomNumberProvider
,我会这样解决:
public void Install(
IWindsorContainer container,
IConfigurationStore store)
{
container.Register(
Component.For<PlayWithDI>());
container.Register(
Component.For<IOutputManager>()
.ImplementedBy<ConsoleOutputManager>());
container.Register(
Component.For<INumberProvider>()
.ImplementedBy<RandomNumberProvider>()
.DependsOn(
Dependency.OnValue("min", 2),
Dependency.OnValue("max", 20)));
container.Register(
Component.For<INumberToWordConverter>()
.ImplementedBy<ItalianNumberToWordConverter>());
}
...
container.Install(new DependenciesConfiguration1());
var testDI = container.Resolve<PlayWithDI>();
testDI.Execute();
当我想在运行时为 RandomNumberProvider
提供自定义参数时出现问题。
我看了一下TypedFactory
,但是这个例子我不是很懂,因为如果我先解析一个factory,那么PlayWithDi应该怎么解析呢?我应该将 INumberProviderFactory 而不是 INumberProvider 传递给它的构造函数吗?
在这种情况下,我想到了这样一个工厂:
public interface INumberProviderFactory
{
INumberProvider Create(
IOutputManager outputManager,
int min, int max);
}
当我再调用Create
时,我应该如何解析outputManager
呢?我很困惑。
The problem arises when I want to give custom parameters to RandomNumberProvider at runtime.
这就是你出错的地方。 Injecting runtime data into components during construction is ananti-pattern:
Don't inject runtime data into application components during construction; it causes ambiguity, complicates the composition root with an extra responsibility and makes it extraordinarily hard to verify the correctness of your DI configuration. [...] Let runtime data flow through the method calls of constructed object graphs.
换句话说,您的 RandomNumberProvider
应该接受 min
和 max
参数是 GenerateNumber
方法的输入参数。