Невозможно объединить Factory/DI

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

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

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

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

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

Любые идеи? Я что-то пропустил?

Ответ 1

Решение по умолчанию для DI, когда вы не можете подключить конкретный тип во время регистрации, заключается в использовании Аннотация 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, позволяя вам оставаться с Инъекцией конструктора.

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

Ответ 2

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

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

С уважением,

Metro.