你为什么要使用Windsor AsFactory?

msw*_*cki 16 c# castle-windsor

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

例:

container.Register(Component.For<IEmailSender>().ImplementedBy<SmtpEmailSender>());
container.Register(Component.For<IEmailSenderFactory>().AsFactory().LifeStyle.Transient);
Run Code Online (Sandbox Code Playgroud)

...

using (var factory = context.GetServiceFactory<IEmailSenderFactory>())
{
    var emailSender = factory.CreateEmailSender();
    emailSender.Send(message);
}
Run Code Online (Sandbox Code Playgroud)

你为什么不写简单:

var emailSender = context.GetServiceFactory<IEmailSender>();
emailSender.Send(message);
Run Code Online (Sandbox Code Playgroud)

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

Pat*_*irk 41

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果没有a number,你就无法解析这个类的实例,也许你也想指定stream(控制台,文件,打印机等等).所以,你定义一个工厂:

public interface INumberWriterFactory
{
    INumberWriter Create(int number);
    INumberWriter Create(int number, IStream stream);
} 
Run Code Online (Sandbox Code Playgroud)

现在,以下代码将起作用:

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();
         }
    }
}
Run Code Online (Sandbox Code Playgroud)

2.引入一个抽象层次

使用工厂可以使您无需更改创建对象的方式.例如,如果您需要创建对象的实例并且每次都使用相同的构造函数参数,则可以创建一个具体的工厂,然后只使用它到处而不是通过生成的那个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<INumberWriter>(number, this.stream);
    }

    public INumberWriter Create(int number, IStream stream)
    {
        return container.Resolve<INumberWriter>(number, stream);
    }
}
Run Code Online (Sandbox Code Playgroud)

没有变化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
}
Run Code Online (Sandbox Code Playgroud)

再次,这是在这个意义上,如果你已经在使用一个工厂接口,如一个使用的有用的AsFactory(),你可以很容易地掉出来了一个新的实现.如果您已经使用容器,那么这样做会更加困难; 找到你需要改变的地方更加困难,更换容器的使用更难以使用新的类型(即工厂).

注意:您必须创建一个INumberWriterFactoryFactory注入IStream混凝土工厂.

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

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

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