Если вам нужно создать зависимость, которая имеет свои зависимости, вы можете либо A) сделать это самостоятельно, либо B) попросить кого-то еще сделать это для вас.Вариант A сводит на нет преимущества внедрения зависимостей (развязки и т. Д.), Поэтому я бы сказал, что вариант B является лучшей отправной точкой.Теперь мы решили использовать шаблон фабрики, независимо от того, принимает ли он форму сервисного локатора (то есть IoC.Resolve
), статической фабрики или фабрики экземпляров.Дело в том, что мы передали эту ответственность внешнему органу.
Для статических методов доступа требуется ряд компромиссов.( Я рассмотрел их в другом ответе , поэтому я не буду повторять их здесь.) Чтобы избежать зависимости от инфраструктуры или контейнера, надежным вариантом является принятие фабрики для создания WithDependencies
когда нам нужен экземпляр где-то еще:
public class NeedsWithDependencies
{
private readonly IWithDependenciesFactory _withDependenciesFactory;
public NeedsWithDependencies(IWithDependenciesFactory withDependenciesFactory)
{
_withDependenciesFactory = withDependenciesFactory;
}
public void Foo()
{
var withDependencies = _withDependenciesFactory.Create();
...Use the instance...
}
}
Далее мы можем создать контейнерную реализацию фабрики:
public class WithDependenciesFactory : IWithDependenciesFactory
{
private readonly IContainer _container;
public WithDependenciesFactory(IContainer container)
{
_container = container
}
public WithDependencies Create()
{
return _container.Resolve<WithDependencies>();
}
}
Теперь NeedsWithDependencies
полностью изолирован отлюбые знания о том, как создается WithDependencies
;он также раскрывает все свои зависимости в своем конструкторе, вместо того, чтобы скрывать зависимости от статических методов доступа, упрощая его повторное использование и тестирование.
Однако определение всех этих фабрик может стать немного громоздким.Мне нравится тип фабричных отношений Autofac , который определяет параметры формы Func<TDependency>
и автоматически вводит функцию, которая выполняет ту же цель, что и фабрика с ручным кодированием, указанная выше:
public class NeedsWithDependencies
{
private readonly Func<WithDependencies> _withDependenciesFactory;
public NeedsWithDependencies(Func<WithDependencies> withDependenciesFactory)
{
_withDependenciesFactory = withDependenciesFactory;
}
public void Foo()
{
var withDependencies = _withDependenciesFactory();
...Use the instance...
}
}
Он также отлично работает с параметрами времени выполнения:
public class NeedsWithDependencies
{
private readonly Func<int, WithDependencies> _withDependenciesFactory;
public NeedsWithDependencies(Func<int, WithDependencies> withDependenciesFactory)
{
_withDependenciesFactory = withDependenciesFactory;
}
public void Foo(int x)
{
var withDependencies = _withDependenciesFactory(x);
...Use the instance...
}
}