你为什么要使用Windsor AsFactory?

为什么要使用Castle Windsor工厂自动实现function:AsFactory()而不是要求所需的接口?

例:

container.Register(Component.For().ImplementedBy()); container.Register(Component.For().AsFactory().LifeStyle.Transient); 

 using (var factory = context.GetServiceFactory()) { var emailSender = factory.CreateEmailSender(); emailSender.Send(message); } 

你为什么不写简单:

 var emailSender = context.GetServiceFactory(); emailSender.Send(message); 

效果是一样的。 Windsor会将IEmailSender解析为默认的注册实现,那么重点是什么呢?

1.注入特定的构造函数参数

有时,当您需要解决它时,您将编写一个需要特定值的类。 例如:

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

2.引入一个抽象层次

使用工厂可以使您无需更改创建对象的方式。 例如,如果您需要创建对象的实例并且每次都使用相同的构造函数参数,则可以创建具体工厂,然后只使用它到处而不是通过AsFactory()生成的AsFactory()

换句话说,我们可以通过在工厂中隐藏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(number, this.stream); } public INumberWriter Create(int number, IStream stream) { return container.Resolve(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注入具体工厂。

3.在组合根中保持IOC容器的使用

有很多人认为只有一个组合根 ,这是唯一一次允许引用IOC容器。 这样做可以帮助您避免多种反模式,例如服务定位器模式。

请注意,这些例子很愚蠢,但我希望他们能够得到这些观点。