Я смущен о внедрении впрыскивания зависимостей в одном конкретном примере.Работа с абстрактной фабрикой, которая вводится через контейнер DI
Предположим, у нас есть класс SomeClass, который имеет зависимость от типа IClassX.
public class SomeClass
{
public SomeClass(IClassX dependency){...}
}
Создания конкретных реализаций интерфейса IClassX зависит от выполнения параметра N.
С данным конструктором, я не могу настроить DI контейнера (Unity используется), потому что я не знаю, что реализация IClassX будет использоваться во время выполнения. Марк Семанн в своей книге «Инъекция зависимостей в .Net» предлагает использовать абстрактную фабрику в качестве параметра впрыска.
Теперь у нас есть SomeAbstractFactory, который возвращает реализации IClassX на основе runtime paramater runTimeParam.
public class SomeAbstractFactory
{
public SomeAbstractFactory(){ }
public IClassX GetStrategyFor(int runTimeParam)
{
switch(runTimeParam)
{
case 1: return new ClassX1();
case 2: return new ClassX2();
default : return new ClassDefault();
}
}
}
SomeClass теперь принимает ISomeAbstractFactory в качестве параметра впрыска:
public class SomeClass
{
public SomeClass(ISomeAbstractFactory someAbstractfactory){...}
}
И это прекрасно. У нас есть только один корневой состав, где мы создаем граф объектов. Мы настраиваем контейнер Unity для ввода SomeAbstractFactory в SomeClass.
Но давайте предположим, что классы ClassX1 и ClassX2 имеют свои собственные зависимости:
public class ClassX1 : IClassX
{
public ClassX1(IClassA, IClassB) {...}
}
public class ClassX2 : IClassX
{
public ClassX2(IClassA, IClassC, IClassD) {...}
}
Как разрешить IClassA, IClassB, IClassC и IClassD зависимостей?
1. Инъекции через SomeAbstractFactory конструктор
Мы можем придать конкретные реализации IClassA, IClassB, IClassC и IClassD к SomeAbstractFactory так:
public class SomeAbstractFactory
{
public SomeAbstractFactory(IClassA classA, IClassB classB, IClassC classC, IClassD classD)
{...}
...
}
Единство контейнер будет использоваться в исходном составной корень, а затем использовать бедный человек DI для возврата бетона ClassX1 или ClassX2 на основе параметра runTimeParam
public class SomeAbstractFactory
{
public SomeAbstractFactory(IClassA classA, IClassB classB, IClassC classC, IClassD classD){...}
public IClassX GetStrategyFor(int runTimeParam)
{
switch(runTimeParam)
{
case 1: return new ClassX1(classA, classB);
case 2: return new ClassX2(classA, classC, classD);
default : return new ClassDefault();
}
}
}
Проблема с этим подходом:
- SomeAbstractFactory знает о зависимости, которые Don `т действительно принадлежат к нему.
- Deeper графа объектов потребуется изменить оба SomeAbstractFactory конструктор и класс реализации
- DI контейнер не будет использоваться для разрешения зависимостей, бедные DI должны мужские использовать
2. Явный вызов DI контейнер
Вместо «новичка» ClassX1 или ClassX2 мы разрешим их с помощью контейнера DI.
public class SomeAbstractFactory
{
public SomeAbstractFactory(IUnityContainer container){...}
public IClassX GetStrategyFor(int runTimeParam)
{
switch(runTimeParam)
{
case 1: return container.Resolve<IClassX>("x1");
case 2: return container.Resolve<IClassX>("x2");
default : return container.Resolve<IClassX>("xdefault");
}
}
}
Проблемы с этим подходом:
- DI контейнер передается в SomeAbstractFactory
- Д.И. Метод Решимость не используется только в корне композиции (ServiceLocator анти-паттерна)
Есть ли еще более подходящий подход?