Подтвердить что ты не робот

Почему вы используете Windsor AsFactory?

Почему вы использовали функцию автоматического запуска Castle Windsor factory: 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 как стандартную зарегистрированную реализацию, так что в чем смысл?

4b9b3361

Ответ 1

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 (консоль, файл, принтер и т.д.). Итак, вы определяете factory:

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. Чтобы ввести уровень абстракции

Использование factory может изолировать вас от изменений в том, как вам нужно создать объект. Например, если вам нужно создавать экземпляры объектов и всегда использовать один и тот же параметр конструктора каждый раз, вы можете создать конкретный factory, а затем просто использовать это везде, а не только сгенерированное с помощью AsFactory().

Другими словами, мы могли бы изменить поведение некоторого кода, закодировав параметр stream в factory, чтобы всегда использовался конкретный поток по умолчанию (например, если 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
}

Опять же, это полезно в том смысле, что если вы уже использовали интерфейс factory, например, реализованный с помощью AsFactory(), вы можете легко заменить его для новой реализации. Выполнение этого, если вы уже использовали контейнер, сложнее; вам сложнее найти места, которые вам нужно изменить, и сложнее заменить использование контейнера для использования нового типа (т.е. a factory).

Примечание: вам нужно создать INumberWriterFactoryFactory, чтобы ввести IStream в конкретный factory.

3. Чтобы сохранить использование контейнера IOC в корне композиции

Там много людей, которые подписываются на идею о том, что существует только один составной корень, и это единственный раз, когда ссылка на Контейнер МОК разрешен. Это может помочь вам избежать нескольких анти-шаблонов, таких как шаблон locator.

Обратите внимание, что эти примеры немыслимы, но я надеюсь, что они получат точки.