DI и параметры времени выполнения - структура карты
Я все больше и больше смешиваю параметры времени выполнения и неявное внедрение в конструкцию, и это плохо пахнет для меня.
Пример - у меня есть базовый класс, описывающий фильтр, и различные унаследованные типы для определенных фильтров (тег, категория, дата, автор и т. Д. И т. Д.)
var filter = StructureMap.ObjectFactory
.With("caption").EqualTo("Posts filtered by tag:")
.With("parameters").EqualTo(parameters)
.With("displayInSummary").EqualTo(true)
.GetInstance<TagListFilter>();
Я делаю это потому, что в конструкторе у меня есть интерфейс, с помощью которого я хочу, чтобы StructureMap внедрял конкретный класс (IArticleConfigurator):
public TagListFilter(string caption, IDictionary<string,string> parameters, bool displayInSummary, IArticleConfigurator configurator)
:base(caption, parameters,displayInSummary, configurator)
Но мне пришло в голову, что я заменил простой конструктор, хотя и на конкретный класс вместо интерфейса, по сути, тем же самым, но с использованием DI для внедрения 1 конкретного типа. Я делаю это, потому что в настоящее время наши конфиги находятся в xml-файле, но будут перенесены в CMS, поэтому было неплохо использовать интерфейс.
Вроде неправильно и не в духе DI.
Должен ли я использовать фабрику для генерации своих различных фильтров? Если да, могу ли я использовать DI, чтобы получить конкретный экземпляр моего IArticleConfigurator?
1 ответ
Вы не должны явно передавать параметры из одной зависимости в другую или, по крайней мере, вы должны минимизировать их количество. Один большой недостаток разрешения экземпляров с параметрами заключается в том, что вы указываете имена параметров в виде строковых литералов, что делает ваш код очень хрупким при изменении сигнатуры конструктора.
Один из примеров, о котором я могу подумать (обратите внимание, что я понятия не имею о вашем домене и обязанностях организаций), - это ввести провайдера или, как вы уже сказали, фабрику. Например, создать что-то вроде ITagListFilterConfigurationProvider
(вы должны изменить имя, как вы хотите, я просто пытаюсь дать мотивацию). Вы можете создать очень абстрактный провайдер, как IFilterConfigurationProvider
с тремя методами, как показано ниже, если у вас есть те же параметры для фильтров:
interface ITagListFilterConfigurationProvider
{
string Caption { get; }
IDictionary<string,string> GetParameters();
bool IsDisplayInSummary { get; }
}
Теперь ваш конструктор будет выглядеть так:
public TagListFilter(ITagListFilterConfigurationProvider configurationProvider, IArticleConfigurator configurator)
Все, что вам нужно, это реализовать его, как вы уже сделали (потому что вы передаете конкретные параметры конструктору), и извлечь это поведение провайдеру. Что осталось - это зарегистрировать конкретного провайдера в StructureMap и разрешить фильтр без передачи каких-либо конкретных параметров.
var filter = StructureMap.ObjectFactory.GetInstance<TagListFilter>();