为什么要使用Castle Windsor工厂自动实现功能:AsFactory()而不是要求所需的接口?
示例:
container.Register(Component.For<IEmailSender>().ImplementedBy<SmtpEmailSender>());
container.Register(Component.For<IEmailSenderFactory>().AsFactory().LifeStyle.Transient);
...
using (var factory = context.GetServiceFactory<IEmailSenderFactory>())
{
var emailSender = factory.CreateEmailSender();
emailSender.Send(message);
}
为什么你不写简单:
var emailSender = context.GetServiceFactory<IEmailSender>();
emailSender.Send(message);
效果是一样的。无论如何,Windsor会将IEmailSender解析为默认注册实现,那又有什么意义呢?
答案 0 :(得分:39)
有时,当您需要解决它时,您将编写一个需要特定值的类。例如:
public class NumberWriter : INumberWriter
{
readonly int number;
readonly IStream stream;
public NumberWriter(int number, IStream stream)
{
this.number = number;
this.stream = stream;
}
public Write()
{
stream.Write(number);
}
}
您无法在没有number
的情况下解析此类的实例,也许您还想指定stream
(控制台,文件,打印机等)。所以,你定义一个工厂:
public interface INumberWriterFactory
{
INumberWriter Create(int number);
INumberWriter Create(int number, IStream stream);
}
现在,以下代码将起作用:
public class RandomNumberGenerator
{
readonly INumberWriterFactory numberWriterFactory;
public RandomNumberGenerator(INumberWriterFactory numberWriterFactory)
{
this.numberWriterFactory = numberWriterFactory;
}
public void Generate()
{
Random random = new Random();
for (int i = 0; i < 10; i++)
{
// Writes to first IStream that Castle can resolve
var numberWriter = numberWriterFactory.Create(random.Next());
numberWriter.Write();
}
}
public void Generate(IStream stream)
{
Random random = new Random();
for (int i = 0; i < 10; i++)
{
// Writes to the given IStream
var numberWriter = numberWriterFactory.Create(random.Next(), stream);
numberWriter.Write();
}
}
}
使用工厂可以使您无需更改创建对象的方式。例如,如果您需要创建对象实例并且每次始终使用相同的构造函数参数,则可以创建具体工厂,然后只使用该工厂而不是通过AsFactory()
生成的工厂。 / p>
换句话说,我们可以通过在工厂中隐藏stream
参数来修改某些代码的行为,以便始终使用特定的默认流(例如,如果IStream
不能只是从容器中解决)。这样做意味着我们根本不需要更改RandomNumberGenerator
:
public class NumberWriterFactory : INumberWriterFactory
{
readonly IStream stream;
readonly IContainer container;
public NumberWriterFactory(IStream stream, IContainer container)
{
this.stream = stream;
this.container = container;
}
public INumberWriter Create(int number)
{
return container.Resolve<INumberWriter>(number, this.stream);
}
public INumberWriter Create(int number, IStream stream)
{
return container.Resolve<INumberWriter>(number, stream);
}
}
RandomNumberGenerator
没有变化,但行为发生了变化:
public class RandomNumberGenerator
{
readonly INumberWriterFactory numberWriterFactory;
public RandomNumberGenerator(INumberWriterFactory numberWriterFactory)
{
this.numberWriterFactory = numberWriterFactory;
}
public void Generate()
{
Random random = new Random();
for (int i = 0; i < 10; i++)
{
// Writes to the IStream instance that the factory contains
var numberWriter = numberWriterFactory.Create(random.Next());
numberWriter.Write();
}
}
// the rest as before
}
同样,这是有用的,如果您已经在使用工厂界面,例如使用AsFactory()
实现的界面,您可以轻松地将其换出以实现新的实现。如果您已经使用容器,那么这样做会更加困难;找到你需要改变的地方更加困难,更换容器的使用更难以使用新的类型(即工厂)。
注意:您必须创建INumberWriterFactoryFactory
以将IStream
注入具体工厂。
有很多人认为只有一个composition root,而仅时间是允许对IOC容器的引用。这样做可以帮助您避免多种反模式,例如service locator模式。
请注意,这些例子很愚蠢,但我希望他们能够得到这些观点。