Инъекция зависимостей и другие параметры конструктора - плохая практика?
В настоящий момент я немного экспериментирую с контейнерами для инъекций зависимостей, на этот раз с Unity.
Учитывая следующий интерфейс:
public interface IPodcastCommService
{
void Download();
void Upload();
}
и следующую реализацию:
public class PodcastService
{
private IPodcastCommService commservice;
private String url;
public PodcastService(String url, IPodcastCommService commservice)
{
this.commservice = commservice;
this.url = url;
}
}
Из-за конструктора я искал решение передать ему параметр и нашел его:
var p = container.Resolve<IPodcastCommService>(new ParameterOverride("url", myUrl));
До сих пор так хорошо, но в то же время я читал о том, насколько это плохо и насколько плох дизайн класса и да, он выглядит немного уродливым. Но как я могу передать параметр классу элегантным способом?
Моя первая мысль заключалась в том, чтобы сделать это как свойство, но тогда я должен проверять каждый раз, когда мне нужен Url, который уже указан.
Update:
Один пример, когда я читал, что это плохой дизайн, заключается в следующем:
Но могут быть случаи, когда вы выполняете параметры пользовательского конструктора для операции разрешения. Некоторые могут утверждать, что это крики плохой архитектуры, но в таких ситуациях, как приведение DI-контейнера в унаследованную систему, которая может потребовать такого рода действия.
Источник: http://mikaelkoskinen.net/unity-passing-constructor-parameters-to-resolve/
Ответы
Ответ 1
Я не понимаю, почему вам нужен PodcastService с составом IPodcastCommService
вместо внедренного IPodcastCommService
и имеет url, введенный строкой. Я не понимаю, почему ваш дизайн плох. Инъекционный URL хорош ИМХО.
Если вы думаете о лучшем способе, я думаю, что его можно заменить, введя контекст/конфигурацию вместо собственного типа данных.
public class PodcastService
{
private IPodcastCommService commservice;
private IConnectionContext connection;
public PodcastService(IConnectionContext connection, IPodcastCommService commservice)
{
this.commservice = commservice;
this.connection= connection;
}
}
public interface IConnectionContext{
string PodcastServiceUrl{get;}
}
Но опять же, я не нахожу никакой пользы от него (за исключением того, что вы можете обрабатывать сессии/константы/статические поля) из обычного подхода.
UPDATE:
Я нашел знакомый вопрос о плохом дизайне здесь. Таким образом, это не так, что параметр родного типа (строка и т.д.) Или настраиваемый параметр конструктора плох. Просто вам нужно поставить параметр в класс, который действительно отвечает за параметр. И настраиваемый параметр конструктора потребуется, если вы обрабатываете условие if-else внутри абстрактного шаблона factory.
Ответ 2
В вашем сценарии я думаю, что DI через конструктор отлично работает. Причина, по которой он считал, что лучше подходит для использования через свойства, заключается в том, что он лучше читается, т.е. Представьте, как выглядит ваш конструктор, если вам нужно было ввести 20 свойств.
Если вы только намереваетесь впрыскивать пару свойств, тогда нет абсолютно никакого вреда, это то, что вы делаете. Я бы подумал о переходе к подходу типа собственности, если вы обнаружите, что ваши зависимости начинают ползать вверх.
Ответ 3
Возможно,
container.RegisterType<PodcastService>(new InjectionConstructor("myUrlParameter"));
будет лучше, не так ли?
но если вам нужно больше одного подкатного сервиса, и им нужен еще один URL-адрес, то переопределить параметр - это нормально.
Ответ 4
Это зависит от используемой структуры yu. Например, точка интеграции провайдеров asp.net mvc для контейнеров IoC, таких как DependecyResolver. Вы должны поместить всю свою логику для построения объектов и ввода зависимостей там. Если вы используете aps.net, у вас может быть какая-то базовая страница, из которой preinit eevnt вводит зависимости. Вы не можете использовать инсталляцию конструктора с asp.net, только вложение свойств. С winforms вы можете использовать какие-то формы factory для создания объектов формы.