Не могу объединить 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 и т. Д.). Это кажется мне излишним.
Если фабрика определена на том же уровне, что и реализация и инициализация Контейнера, я не вижу слабой ссылки на контейнер со стороны фабрики. Он по-прежнему предотвращает утечку ссылок контейнера в остальную часть вашего приложения.
С наилучшими пожеланиями,
Метро.