Не могу объединить Factory / DI - PullRequest
       49

Не могу объединить Factory / DI

44 голосов
/ 18 декабря 2009

Просто предположим, что у меня есть некоторый класс Foo, который имеет две зависимости: ISerializer<T> и IFileAccessHandler.

Теперь у этого класса также есть другие зависимости, функциональные зависимости. Я не хочу, чтобы кто-либо создавал этот класс в недопустимом состоянии, поэтому мне также нужно передать объект домена в конструкторе.

Но как мне справиться с этим IoC, когда я также знаю, какой объект домена должен быть передан в момент, когда я фактически создаю класс Foo?

Я сделал объект домена свойством, которое я установил Фабрикой. Таким образом, Factory делает вызов Service Locator, чтобы получить экземпляр класса Foo с его зависимостями, который создается должным образом, а затем заполняет его правильным доменным объектом и возвращает его.

Но разве это лучший путь? Я бы предпочел, чтобы доменный объект был частью моего конструктора, чтобы он был вполне подходящим для работы с "Foo".

Есть идеи? Я что-то здесь упускаю?

Ответы [ 2 ]

70 голосов
/ 18 декабря 2009

Решение DI по умолчанию, когда вы не можете подключить конкретный тип во время регистрации, - это использовать Абстрактная фабрика

В вашем случае я бы определил интерфейс IFooFactory:

public interface IFooFactory
{
    Foo Create(DomainClass dc);
}

Это позволит вам определить конкретную реализацию, которая знает о ваших инфраструктурных сервисах.

public class FooFactory : IFooFactory
{
    private readonly ISerializer serializer;
    private readonly IFileAccessHandler fileHandler;

    public FooFactory(ISerializer serializer, IFileAccessHandler fileHandler)
    {
        if(serializer == null)
        {
            throw new ArgumentNullException("serializer");
        }
        if(fileHandler == null)
        {
            throw new ArgumentNullException("fileHandler");
        }

        this.serializer = serializer;
        this.fileHandler = fileHandler;
    }

    public Foo Create(DomainClass dc)
    {
        return new Foo(this.serializer, this.fileHandler, dc);
    }
}

Таким образом, вы можете защитить инварианты вашего класса Foo, что позволит вам остаться с Конструктор Инъекция .

В контейнере DI вы можете зарегистрировать IFooFactory и соответствующую реализацию. Везде, где у вас есть экземпляр DomainClass и вам нужен экземпляр Foo, вы должны взять зависимость от IFooFactory и использовать ее.

0 голосов
/ 19 июня 2013

Я тоже борюсь с этой проблемой. Пример Марка ограничен в том, что FooFactory создает конкретный класс Foo. Что если бы создать IFoo, где реализация определяется во время настройки запуска? Это подразумевает, что для каждой альтернативной реализации IFoo (FooA, FooB и т. Д.) Вам потребуется конкретная реализация соответствующей фабрики (FooAFactory, FooBFactory и т. Д.). Это кажется мне излишним.

Если фабрика определена на том же уровне, что и реализация и инициализация Контейнера, я не вижу слабой ссылки на контейнер со стороны фабрики. Он по-прежнему предотвращает утечку ссылок контейнера в остальную часть вашего приложения.

С уважением,

Metro.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...