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

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

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

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

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

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

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

2 ответа

Решение

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

В вашем случае я бы определил интерфейс 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, что позволит вам оставаться в Constructor Injection.

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

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

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

С наилучшими пожеланиями,

Метро.

Другие вопросы по тегам