598

Я использую Dependency Injection (DI) некоторое время, впрыскивая либо в конструктор, свойство, либо метод. Я никогда не чувствовал необходимости использовать контейнер Inversion of Control (IoC). Однако, чем больше я читаю, тем больше я испытываю давление со стороны сообщества на использование контейнера IoC.Зачем нужен контейнер IoC, а не простой код DI?

Я играл с контейнерами .NET, такими как StructureMap, NInject, Unity и Funq. Я все еще не понимаю, как контейнер IoC будет полезен/улучшит мой код.

Я также боюсь начать использовать контейнер на работе, потому что многие из моих коллег увидят код, который они не понимают. Многие из них могут неохотно изучать новые технологии.

Пожалуйста, убедите меня, что мне нужно использовать контейнер IoC. Я буду использовать эти аргументы, когда я буду говорить с моими коллегами-разработчиками на работе.

+6

Хороший вопрос. Я отвечаю на это в комментариях, поскольку я очень новичок в идее МОК. Похоже на идею компонентов plug and play и развязки. Если у вас будет необходимость использовать какой-либо другой компонент вместо текущего, это необходимо. Использование МОК заключается в подготовке кода для такого изменения, если оно возникает в ИМО. – shahkalpesh

+3

@shahkalpesh, но я могу достичь свободной связи с простым DI. Однако я вижу вашу точку зрения, если я использую файл конфигурации. Однако я не уверен, что мне нравится использовать конфигурационный файл. Файлы Config очень многословны, трудности с рефакторингом и переключение между несколькими файлами. – Vadim

+110

просто добавляете комментарий, так как кажется, что вы ищете причины использовать IoC в основном; но что-то еще нужно сказать о вашей проблеме. Вы не можете написать свой код на уровень худшего человека в вашей команде или опасаться, что они не захотят учиться. У вас есть ответственность не только за то, чтобы быть профессионалом, но и за ваше будущее расти, и ваша команда не должна вас удерживать. –

ответ

441

Вау, не могу поверить, что Джоэл предпочли бы это:

var svc = new ShippingService(new ProductLocator(), 
    new PricingService(), new InventoryService(), 
    new TrackingRepository(new ConfigProvider()), 
    new Logger(new EmailLogger(new ConfigProvider()))); 

по этому поводу:

var svc = IoC.Resolve<IShippingService>(); 

Многие люди не понимают, что ваша зависимости цепь может стать вложенным, и это быстро становится громоздким, чтобы подключить их вручную. Даже на фабриках дублирование вашего кода просто не стоит.

Контейнеры IoC могут быть сложными, да. Но для этого простого случая я показал, что это невероятно просто.


Хорошо, давайте оправдываем это еще больше. Допустим, у вас есть объекты или объекты модели, которые вы хотите привязать к интеллектуальному интерфейсу. Этот интеллектуальный интерфейс (мы будем называть его Shindows Morms) хочет, чтобы вы реализовали INotifyPropertyChanged, чтобы он мог отслеживать изменения & соответствующим образом обновлять пользовательский интерфейс.

«Хорошо, это звучит не так сложно», чтобы вы начали писать.

Вы начинаете с этим:

public class Customer 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public DateTime CustomerSince { get; set; } 
    public string Status { get; set; } 
} 

..и в итоге это:

public class UglyCustomer : INotifyPropertyChanged 
{ 
    private string _firstName; 
    public string FirstName 
    { 
     get { return _firstName; } 
     set 
     { 
      string oldValue = _firstName; 
      _firstName = value; 
      if(oldValue != value) 
       OnPropertyChanged("FirstName"); 
     } 
    } 

    private string _lastName; 
    public string LastName 
    { 
     get { return _lastName; } 
     set 
     { 
      string oldValue = _lastName; 
      _lastName = value; 
      if(oldValue != value) 
       OnPropertyChanged("LastName"); 
     } 
    } 

    private DateTime _customerSince; 
    public DateTime CustomerSince 
    { 
     get { return _customerSince; } 
     set 
     { 
      DateTime oldValue = _customerSince; 
      _customerSince = value; 
      if(oldValue != value) 
       OnPropertyChanged("CustomerSince"); 
     } 
    } 

    private string _status; 
    public string Status 
    { 
     get { return _status; } 
     set 
     { 
      string oldValue = _status; 
      _status = value; 
      if(oldValue != value) 
       OnPropertyChanged("Status"); 
     } 
    } 

    protected virtual void OnPropertyChanged(string property) 
    { 
     var propertyChanged = PropertyChanged; 

     if(propertyChanged != null) 
      propertyChanged(this, new PropertyChangedEventArgs(property)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

Отвратительно код сантехника, и я утверждаю, что если вы пишете такой код от руки вы крадете у своего клиента. Есть лучший, более умный способ работы.

Вы когда-нибудь слышали этот термин, работайте умнее, а не сложнее?

Ну представьте, какой умный парень на вашей команде подошел и сказал: «Вот простой способ»

Если вы сделаете ваши свойства виртуальными (успокойтесь, это не то, что крупные сделки), то мы можем переплетения. (Это называется АОП, но не беспокойтесь об имени, сосредоточить внимание на том, что он собирается сделать для вас)

В зависимости от IoC инструмент вы используете, вы могли бы сделать что-то, что выглядит следующим образом:

var bindingFriendlyInstance = IoC.Resolve<Customer>(new NotifyPropertyChangedWrapper()); 

Пуф! Все это руководство INotifyPropertyChanged BS теперь автоматически генерируется для вас, на каждом виртуальном устройстве, задающем объект.

Это волшебство? ДА! Если вы можете доверять факту, что этот код выполняет свою работу, тогда вы можете смело пропустить все это свойство, обертывающее mumbo-jumbo. У вас проблемы с бизнесом.

некоторых других интересных применений инструмента IoC делать АОП:

  • декларативные & вложенных транзакций базы данных
  • декларативной & вложенной Единица работы
  • Logging
  • Pre/Post условия (дизайн по Договор)
+2

Отличное дополнение. Я часто нахожу, что я делаю такую ​​сантехнику для объекта. Теперь я открою свой ум для IoC и посмотрю, что это может быть учтено. –

+3

Кроме того, какой инструмент IoC вы тоже имеете в виду? –

+28

К сожалению, вы забыли сделать все свойства виртуальными, и это не сработало. Это время, необходимое для отладки этого кражи со своего клиента? (Извините, если вы не используете DynamicProxy.: P) – Thom

32

По моему мнению, преимуществом IoC в первом случае является возможность централизовать конфигурацию ваших зависимостей.

Если вы используете Dependency Injection ваш код может выглядеть следующим образом

public class CustomerPresenter 
{ 
    public CustomerPresenter() : this(new CustomerView(), new CustomerService()) 
    {} 

    public CustomerPresenter(ICustomerView view, ICustomerService service) 
    { 
    // init view/service fields 
    } 
    // readonly view/service fields 
} 

Если используется статический класс IoC, в отличие от, ИМХО более запутанным, конфигурационные файлы, вы могли бы что-то вот так:

public class CustomerPresenter 
{ 
    public CustomerPresenter() : this(IoC.Resolve<ICustomerView>(), IoC.Resolve<ICustomerService>()) 
    {} 

    public CustomerPresenter(ICustomerView view, ICustomerService service) 
    { 
    // init view/service fields 
    } 
    // readonly view/service fields 
} 

Тогда ваш статический класс IoC будет выглядеть так, я использую Unity здесь.

public static IoC 
{ 
    private static readonly IUnityContainer _container; 
    static IoC() 
    { 
    InitializeIoC(); 
    } 

    static void InitializeIoC() 
    { 
     _container = new UnityContainer(); 
     _container.RegisterType<ICustomerView, CustomerView>(); 
     _container.RegisterType<ICustomerService, CustomerService>(); 
     // all other RegisterTypes and RegisterInstances can go here in one file. 
     // one place to change dependencies is good. 
    } 
} 
+11

Бен, то, о чем вы говорите, действительно является местом службы, а не инжекцией зависимостей - есть разница. Я всегда предпочитаю первое по сравнению с последним. http://stevenharman.net/blog/archive/2009/09/25/prefer-dependency-injection-to-service-location.aspx – stevenharman

+23

Вместо того чтобы делать IoC.Resolve в вашем конструкторе по умолчанию, вы должны использовать способность контейнера IOC для создания объекта для вас. Избавьтесь от этого пустого конструктора и пусть контейнер IOC построит для вас объект. var presenter = IoC.Resolve (); voila! все зависимости уже подключены. –

+0

@ben, Согласен! но не забывайте о том, что это место обслуживания расположено в каком-то уголке вашей инфраструктуры, что ограничивает использование местоположения как можно меньшим количеством мест. – stevenharman

8

Поскольку вся зависимость хорошо видна, что способствует созданию компонентов, которые слабо связаны и в то же время легко доступны и повторно через приложение.

27

Использование контейнера в основном об изменении из императивных/сценария стиля инициализации и конфигурации в декларативной один. Это может иметь несколько различных положительных эффектов:

  • Сокращение hairball процедур запуска основной программы.
  • Включение возможностей глубокой реверсификации времени развертывания.
  • Применяя стиль зависимости от инъекций - путь наименьшего сопротивления для новой работы.

Конечно, могут возникнуть трудности:

  • Код, который требует комплексного управления включения/выключения/жизненный цикл не может быть легко адаптирована к контейнеру.
  • Вам, вероятно, придется ориентироваться на любые личные, процессуальные и командные проблемы, - но потом, вот почему вы спросили ...
  • Некоторые из наборов инструментов быстро становятся тяжеловесными, поощряя такую ​​глубокую зависимость, что многие Контейнеры DI запускались как обратная реакция.
137

Я с вами, Вадим.Контейнеры IoC используют простую, элегантную и полезную концепцию и делают это, что вам нужно изучить в течение двух дней с помощью 200-страничного руководства.

Я лично недоумеваю, как сообщество IoC приняло красивый, elegant article by Martin Fowler и превратило его в кучу сложных фреймворков, обычно с 200-300 справочниками страниц.

Я стараюсь не осуждать (HAHA!), Но я думаю, что люди, которые используют контейнеры IoC, (A) очень умны и (B) не имеют сочувствия к людям, которые не так умны, как они. Все имеет для них смысл, поэтому им трудно понять, что многие обычные программисты найдут концепцию запутанной. Это curse of knowledge. Люди, которые понимают контейнеры IoC, не могут поверить, что есть люди, которые этого не понимают.

Наиболее ценным преимуществом использования контейнера IoC является то, что вы можете иметь переключатель конфигурации в одном месте, что позволяет вам переключаться между, скажем, тестовым режимом и режимом производства. Например, предположим, что у вас есть две версии классов доступа к базе данных ... одна версия, которая была зарегистрирована агрессивно и провела большую проверку, которую вы использовали во время разработки, и другую версию без регистрации или проверки, которая была критически быстрой для производства. Приятно переключаться между ними в одном месте. С другой стороны, это довольно простая задача, которую легко обрабатывать проще, без сложностей контейнеров IoC.

Я считаю, что если вы используете контейнеры IoC, ваш код станет, честно говоря, намного сложнее читать. Количество мест, которые вы должны посмотреть, чтобы выяснить, что пытается сделать код, увеличивается, по крайней мере, на один. И где-то на небесах кричит ангел.

+15

Если я могу сказать, это похоже на другой взгляд на мир для разных людей. Люди, которые используют МОК, подобны идеологам, которые хотят, чтобы мир следовал их шагам, а затем есть другие, подобные мне (и другим разработчикам), которые застряли между идеологией и реальностью;) – shahkalpesh

+7

Не могу согласиться. Начал изучать использование каркаса DI (StructureMap), который утверждает, что он является самым старым контейнером IoC. Сложность была ошеломляющей, учитывая то, что я хотел. Вместо этого я пишу свой очень простой сервис-локатор. Возможно, один из других контейнеров IoC имел бы больше смысла, но я действительно не вижу смысла, и у меня нет времени потратить несколько дней на то, чтобы выяснить, как использовать что-то, что сделает чтение кода более сложным. – eesh

+14

Мартин Фаулер, будучи великим автором, никоим образом не изобретал IoC. –

28

Я поклонник декларативного программирования (посмотрите, сколько ответов на SQL-вопросы я отвечу), но контейнеры IoC, на которые я смотрел, кажутся слишком тайными для их же блага.

... или, возможно, разработчики контейнеров IoC не могут писать четкую документацию.

... или оба они верны в той или иной степени.

Я не думаю, что концепция контейнера IoC плохая. Но реализация должна быть как мощной (то есть гибкой), достаточной для использования в самых разных приложениях, но простой и понятной.

Это, вероятно, шесть из одной и полудюжины другой. Реальное приложение (а не игрушка или демо) должно быть сложным, учитывая множество угловых случаев и исключений из правил. Либо вы инкапсулируете эту сложность в императивный код, либо в декларативный код. Но вы должны представлять это где-то.

+5

Мне нравится ваше наблюдение о неизбежном присутствии сложности. Разница между проводкой на основе контейнеров и ручной зависимостью заключается в том, что с использованием контейнера вы можете сосредоточиться на каждом компоненте индивидуально и, таким образом, управлять усложнением довольно линейным способом. Системы с ручным подключением с зависимостями более сложны для развития, поскольку действие настройки одного компонента трудно изолировать от настройки всего остального. –

+0

Мне нравится AspectJ. Это не Java, но это тоже не XML. Это своего рода * IS * Java, поскольку он чувствует и выглядит как Java, будучи его расширением. Я бы предпочел оставить свои аспекты вне своих POJO и моей бизнес-логики. Я почти хотел бы сохранить мои IoCs. Там очень много XML в подключении инструментов, ИМХО. Если у меня есть файлы конфигурации, пусть они будут скриптами BeanShell./Java, примените ваши .Net-рабочие здесь ->. –

+2

Я, безусловно, понимаю ваш ответ, но я думаю, что большая часть проблемы заключается в том, что многие рамки IoC (и, действительно, многие другие структуры для других вещей тоже) описаны и документированы для других, уже очень хорошо знакомых с необходимыми понятиями и терминологией. Я узнаю о многом, просто наследуя код другого программиста. Я изо всех сил пытаюсь понять, почему код использует IoC, когда «графические объекты» довольно малы и нет никакого реального покрытия кода. Как программист SQL, вы, вероятно, можете лучше использовать IoC с ORM. –

32

Контейнеры IoC также полезны для загрузки глубоко вложенных зависимостей классов. Например, если у вас был следующий код с использованием Injection Depedency.

public void GetPresenter() 
{ 
    var presenter = new CustomerPresenter(new CustomerService(new CustomerRepository(new DB()))); 
} 

class CustomerPresenter 
{ 
    private readonly ICustomerService service; 
    public CustomerPresenter(ICustomerService service) 
    { 
     this.service = service; 
    } 
} 

class CustomerService 
{ 
    private readonly IRespository<Customer> repository; 
    public CustomerService(IRespository<Customer> repository) 
    { 
     this.repository = repository; 
    } 
} 

class CustomerRepository : IRespository<Customer> 
{ 
    private readonly DB db; 
    public CustomerRepository(DB db) 
    { 
     this.db = db; 
    } 
} 

class DB { } 

Если у вас все из этих зависимостей, загруженных в контейнер и IoC можно Устраните CustomerService и все дочерние зависимости автоматически разрешаются.

Например:

public static IoC 
{ 
    private IUnityContainer _container; 
    static IoC() 
    { 
     InitializeIoC(); 
    } 

    static void InitializeIoC() 
    { 
     _container = new UnityContainer(); 
     _container.RegisterType<ICustomerService, CustomerService>(); 
     _container.RegisterType<IRepository<Customer>, CustomerRepository>(); 
    } 

    static T Resolve<T>() 
    { 
     return _container.Resolve<T>(); 
    } 
} 

public void GetPresenter() 
{ 
    var presenter = IoC.Resolve<CustomerPresenter>(); 
    // presenter is loaded and all of its nested child dependencies 
    // are automatically injected 
    // - 
    // Also, note that only the Interfaces need to be registered 
    // the concrete types like DB and CustomerPresenter will automatically 
    // resolve. 
} 
+0

Но класс IoC вызывается с помощью анти-шаблона локатора сервисов. Should_container передается с использованием конструктора DI вместо вызова static T Resolve ()? –

+0

@bendewey Ваш пример подразумевает, что он автоматически передает аргументы конструкторам для нового CustomerService и нового CustomerRepository. Так ли это работает? Что делать, если у вас есть и другие дополнительные параметры? – Brain2000

17

Я думаю, что большая часть стоимости в IoC это получил с помощью DI. Поскольку вы уже это делаете, остальная часть пособия увеличивается.

Значение, которое вы получите, будет зависеть от типа приложения вы работаете:

  • Для мульти-арендатора, контейнер IoC может позаботиться о некоторых из кода инфраструктуры для загрузки различных клиентских ресурсов. Когда вам нужен компонент, специфичный для клиента, используйте настраиваемый селектор для обработки логики и не беспокойтесь об этом из кода клиента. Вы можете, конечно, построить это самостоятельно, но here's an example о том, как IoC может помочь.

  • Со многими точками расширяемости IoC можно использовать для загрузки компонентов из конфигурации. Это обычная вещь для сборки, но инструменты предоставляются контейнером.

  • Если вы хотите использовать АОП для некоторых сквозных задач, IoC provides hooks для вызова методов перехвата. Это менее часто делается ad-hoc для проектов, но IoC облегчает его работу.

Я написал функциональность, как это раньше, но если мне нужно какая-либо из этих функций теперь я предпочел бы использовать предварительно построенный и испытанный инструмент, если это соответствует моей архитектуре.

Как уже упоминалось, вы также можете централизованно настроить классы, которые вы хотите использовать. Хотя это может быть хорошо, это связано со стоимостью неправильного направления и сложности. Основные компоненты для большинства приложений не заменяются, поэтому компромисс немного сложнее сделать.

Я использую контейнер IoC и ценю функциональность, но должен признать, что я заметил компромисс: мой код становится более ясным на уровне класса и менее ясен на уровне приложения (т. Е. Визуализирует поток управления).

2

В мире .NET AOP не слишком популярна, поэтому для DI каркас - это ваш единственный реальный вариант, независимо от того, пишете ли вы себя или используете другую фреймворк.

Если вы использовали AOP, вы можете вставлять при компиляции своего приложения, которое чаще встречается в Java.

Существует много преимуществ DI, таких как уменьшение связи, поэтому модульное тестирование проще, но как вы его реализуете? Вы хотите использовать отражение, чтобы сделать это самостоятельно?

+0

Новая инфраструктура MEF позволяет только это для .NET, и я должен сказать, что код чище и понятнее, значительно упрощает понимание концепции DI. – terjetyl

+4

@TT: MEF является * не * контейнером для инъекций зависимостей и не имеет ничего общего с АОП. –

23

Звучит так же, как . Вы уже создали свой собственный контейнер IoC (используя различные шаблоны, которые были описаны Мартином Фаулером) и спрашивают, почему реализация кого-то лучше, чем ваша.

Итак, у вас есть куча кода, который уже работает. И задаются вопросом, почему вы хотели бы заменить его чужой реализацией.

Pros для рассмотрения стороннего производителя IoC контейнера

  • Вы получаете ошибки, установленные для свободного дизайна
  • библиотеки может быть лучше, чем ваш
  • Людей могут быть уже знакомы с конкретной библиотекой
  • Библиотека может быть быстрее, чем ваша
  • Возможно, у вас есть некоторые функции, которые вы хотели бы реализовать, но так и не успели (do y У вас есть локатор обслуживания?)

Против

  • Вы получаете ошибки введены, для свободного дизайна :)
  • библиотеки может быть хуже, чем ваш
  • Вы должны выучить новый API
  • Too многие функции, которые вы никогда не будете использовать
  • Как правило, сложнее отлаживать код, который вы не писали
  • Перехода от предыдущего контейнера IoC может быть утомительным

Итак, взвесьте все за против своих минусов и принять решение.

+0

Я согласен с тобой. Сэм - Д.И. - это тип IoC, поэтому, если оригинальный плакат делает DI, они уже делают IoC, поэтому реальный вопрос - это то, почему нужно сворачивать свои собственные. –

+3

Я не согласен. МОК - это способ сделать ДИ. Контейнеры IOC выполняют DI, беря на себя управление типом создания экземпляра, используя динамическое отражение во время выполнения, чтобы удовлетворить и вводить зависимости. ОП указывает, что он делает статический DI и размышляет над тем, почему ему нужно торговать преимуществами проверки времени компиляции на преимущества, часто связанные с динамическим анализом времени выполнения IOC. – Maxm007

37

Предположительно никто не заставляет вас использовать каркас контейнера DI. Вы уже используете DI, чтобы разделить свои классы и улучшить тестируемость, поэтому вы получаете много преимуществ. Короче говоря, вы предпочитаете простоту, что обычно хорошо.

Если ваша система достигает уровня сложности, когда ручной DI становится тяжелой работой (то есть увеличивает обслуживание), взвесьте это на основе командной кривой обучения в каркасе контейнера DI.

Если вам нужно больше контролировать управление жизненным циклом зависимостей (то есть, если вы чувствуете необходимость реализации шаблона Singleton), посмотрите на контейнеры DI.

Если вы используете контейнер DI, используйте только те функции, которые вам нужны. Пропустите файл конфигурации XML и настройте его в коде, если этого достаточно. Придерживайтесь инъекции конструктора. Основы Unity или StructureMap можно свести к нескольким страницам.

Там отличный пост в блоге Марка Seemann на этом: When to use a DI Container

+0

Очень хороший ответ. Единственное, на что я бы поразмыслил, - это то, можно ли считать ручную инъекцию EVER менее сложной или не трудоемкой. – wekempf

+0

+1. Один из лучших ответов здесь. Спасибо также за ссылку на статью в блоге. – stakx

+1

+1 для сбалансированной точки зрения. Контейнеры IoC не всегда хороши, и они не всегда плохие. Если вы не видите необходимости, не используйте его. Просто знайте, что инструмент есть, если вы видите необходимость. – Phil

5

Как вы продолжать разъединять классы и инвертировать вашу зависимость, классы продолжают оставаться небольшими и «граф зависимостей» продолжает расти в размерах. (Это неплохо.) Использование основных функций контейнера IoC делает подключение всех этих объектов тривиальным, но выполнение этого вручную может стать очень обременительным. Например, что, если я хочу создать новый экземпляр «Foo», но ему нужен «Бар». И «Бар» нуждается в «A», «B» и «C». И каждый из них нуждается в 3 других вещах и т. Д. (Да, я не могу придумать хорошие поддельные имена :)).

Использование контейнера IoC для построения графика объекта для вас снижает сложность тонны и выталкивает ее в единую конфигурацию. Я просто говорю: «Создайте меня« Foo », и он выясняет, что нужно для его создания.

Некоторые люди используют контейнеры IoC для гораздо большей инфраструктуры, что отлично подходит для расширенных сценариев, но в этих случаях я согласен, что он может запутываться и сделать код трудным для чтения и отладки для новых разработчиков.

+1

Почему мы продолжаем успокаивать самый низкий общий знаменатель, а не работать, чтобы подтянуть их? – stevenharman

+4

Я ничего не говорил об умиротворении. Я просто сказал, что расширенные сценарии могут сделать вещи более запутанными для новых разработчиков - это факт. Я не сказал «так не делай этого». Но даже тогда (время для адвоката дьявола) часто бывают другие способы сделать то же самое, что делает кодовую базу более явной и доступной.Скрывать сложность в пользовательской конфигурации вашего инструмента инфраструктуры просто потому, что вы можете это не правильно, и он никого не поднимает. –

-8

Зависимость Инъекция в проект ASP.NET может выполняться несколькими строками кода. Я полагаю, что есть преимущество в использовании контейнера, когда у вас есть приложение, которое использует несколько передних концов и требует модульных тестов.

+1

можете ли вы привести пример? Как DI отличается в ASP.NET по сравнению с любым другим типом приложения? – tofi9

0

Лично я использую IoC как своего рода структурную карту моего приложения (да, я также предпочитаю StructureMap;)). Это упрощает замену моих реализаций пользовательского интерфейса с реализацией Moq во время тестов. Создание тестовой установки может быть так же просто, как сделать новый init-call для моей инфраструктуры IoC, заменив класс, который является моей тестовой границей, с макетом.

Это, вероятно, не то, что IoC это там, но это то, что я считаю себя, используя его для самых ..

6

Я просто так случиться, чтобы быть в процессе дергает из дома выращенный код DI и заменить его с МОК. Я, вероятно, удалил более 200 строк кода и заменил его примерно на 10. Да, мне нужно было немного узнать о том, как использовать контейнер (Winsor), но я инженер, работающий над интернет-технологиями в 21-го века, поэтому я привык к этому. Вероятно, я потратил около 20 минут на то, как надо. Это было достойно моего времени.

+3

«Но я инженер, работающий над интернет-технологиями в 21 веке, поэтому я привык к этому» -> +1 – user96403

9

Всякий раз, когда вы используете «новое» ключевое слово, вы создаете конкретную зависимость класса, и маленький колокол будильника должен уйти в голове. Испытание этого объекта становится сложнее изолировать. Решение состоит в том, чтобы программировать на интерфейсы и вводить зависимость, чтобы объект мог тестироваться с помощью всего, что реализует этот интерфейс (например, mocks).

Проблема в том, что вы должны где-то конструировать объекты. Шаблон Factory - это один из способов сдвинуть соединение из ваших POXO (Plain Old), вставьте свой OO-язык здесь «Объекты». Если вы и ваши сотрудники все пишете такой код, то контейнер IoC является следующим «дополнительным улучшением», которое вы можете сделать для своей кодовой базы. Это сместит весь этот неприятный заводский шаблонный код из ваших чистых объектов и бизнес-логики. Они получат это и полюбят его. Черт возьми, расскажи о том, почему ты любишь его и вызываешь у всех.

Если ваши сотрудники еще не делают DI, я бы посоветовал вам сосредоточиться на этом в первую очередь. Разместите слово о том, как писать чистый код, который легко проверить. Чистый код DI является сложной частью, как только вы там, переключение логики проводки объекта из классов Factory в контейнер IoC должно быть относительно тривиальным.

4

Dittos о Единстве. Слишком большой, и ты слышишь скрип в стропилах.

Это никогда не удивляет меня, когда люди начинают рассказывать о том, как выглядят чистые коды кода IoC, те же самые люди, которые в свое время говорили о том, как шаблоны на C++ были изящным способом вернуться в 90-е годы, но в наши дни осуждайте их как тайные. Бах!

14

Наибольшее преимущество использования контейнеров IoC для меня (лично, я использую Ninject) заключалось в том, чтобы исключить прохождение настроек и других видов глобальных объектов состояния.

Я не программирую для Интернета, мое консольное приложение и во многих местах глубоко в дереве объектов мне нужно иметь доступ к настройкам или метаданным, указанным пользователем, которые созданы на совершенно отдельной ветке дерево объектов. С IoC я просто говорю Ninject рассматривать настройки как одноэлементные (потому что их всегда есть только один экземпляр), запросите настройки или словарь в конструкторе и престо ... они волшебным образом появляются, когда они мне нужны!

Без использования контейнера IoC мне пришлось бы передавать настройки и/или метаданные вниз через объекты 2, 3, ..., n, прежде чем он был фактически использован требуемым им объектом.

Есть много других преимуществ для контейнеров DI/IoC, поскольку другие люди подробно описывают здесь, и переход от идеи создания объектов к запрашивающим объектам может быть изгиб ума, но использование DI было очень полезно для меня и моей команды, поэтому, возможно, вы можете добавить его в свой арсенал!

+2

Это огромный плюс. Не могу поверить, что никто еще не упомянул об этом раньше. Без необходимости прохождения или хранения темпоральных объектов код намного чище. – Finglas

+0

«они волшебным образом появляются, когда они мне нужны!» - Я могу сказать вам маленький секрет - просто используйте глобальные объекты, и они волшебным образом появляются, когда вам это нужно, без каких-либо раздутий iocc! – qble

+1

@qble глобальные объекты отлично работают ... если вы хотите, чтобы ваша база кода была тесно связанным, не проверяемым кошмаром, который со временем становится сложнее и сложнее. Удачи с этим. –

14

рамки IoC отлично, если вы хотите ...

  • ... выбросить типобезопасность. Многие (все?) Рамки IoC заставляют вас выполнять код, если вы хотите быть уверенным, что все правильно подключено. «Эй, надеюсь, у меня все настроено так, что мои инициализации этих 100 классов не сбой в производстве, выброс исключений нулевого указателя!»

  • ... мусор ваш код с глобальными (IoC рамки все об изменении глобальных состояний).

  • ... напишите crappy code с нечеткими зависимостями, которые трудно реорганизовать, поскольку вы никогда не узнаете, что от этого зависит.

Проблема с IoC является то, что люди, которые используют их использовали для написания кода, как этого

public class Foo { 
    public Bar Apa {get;set;} 
    Foo() { 
     Apa = new Bar(); 
    } 
} 

который явно испорчен, так как зависимость между Foo и Bar является зашитой. Затем они поняли, что было бы лучше написать код, например

public class Foo { 
    public IBar Apa {get;set;} 
    Foo() { 
     Apa = IoC<IBar>(); 
    } 
} 

, который также является ошибочным, но, что менее очевидно. В Haskell тип Foo() будет IO Foo, но вы действительно не хотите, чтобы IO -part и должен быть предупреждающим знаком о том, что что-то не так с вашим дизайном, если вы его получили.

Чтобы избавиться от него (IO-часть), получите все преимущества IoC-фреймворков, и ни один из его недостатков вы могли бы использовать абстрактную фабрику.

Правильное решение было бы что-то вроде

data Foo = Foo { apa :: Bar } 

или, может быть,

data Foo = forall b. (IBar b) => Foo { apa :: b } 

и инъекционные (но я бы не назвал это инъекционные) Бар.

также: посмотреть видео с Эриком Мейером (изобретатель LINQ), где он говорит, что DI для людей, которые не знают математику (и я не могу не согласиться): http://www.youtube.com/watch?v=8Mttjyf-8P4

В отличие от г Спольски Я не считаю, что люди, которые используют IoC-рамки, очень умны - я просто считаю, что они не знают математики.

+9

отбросить тип безопасности - за исключением того, что ваш пример по-прежнему безопасен, вот что такое интерфейс. Вы не просматриваете типы объектов, а тип интерфейса. И в любом случае безопасность типов не устраняет нулевые ссылочные исключения, вы можете с удовольствием передавать нулевые ссылки в качестве параметров безопасного типа - это вообще не проблема безопасности типов. – blowdart

+0

Вы выбрасываете тип безопасности, так как вы не знаете, подключен ли тип или нет в контейнере IoC (тип IoC не 'IBar', это фактически' IO IBar') .. И да , в примере Haskell я не могу получить нулевую ссылку. – finnsson

+0

Тип безопасности не относится к объекту, который подключен, по крайней мере, не к Java/C#, это просто о том, что объект имеет правильный тип. И ConcreteClass myClass = null по-прежнему имеет правильный тип. Если вы хотите, чтобы принудительное исполнение не было нулевым, тогда кодовые контракты вступают в игру. – blowdart

7

Вам не нужно контейнер IoC.

Но если вы строго следуете образцу DI, вы обнаружите, что с его помощью будет удалена тонна избыточного, скучного кода.

Это часто лучшее время для использования библиотеки/фреймворка, так или иначе - когда вы понимаете, что это делает, и можете делать это без библиотеки.

10

Я обнаружил, что правильная реализация Injection Dependency стремится заставить программистов использовать множество других методов программирования, которые помогают улучшить тестируемость, гибкость, удобство и масштабируемость кода: такие практики, как принцип единой ответственности, разделение Обеспокоенность и кодирование API. Мне кажется, что я вынужден писать более модульные классы и методы, связанные с укусом, что делает код более удобным для чтения, потому что его можно использовать в кусках размером с укусом.

Но также имеет тенденцию создавать довольно большие деревья зависимостей, которые гораздо легче управляются через фреймворк (особенно если вы используете соглашения), чем вручную. Сегодня я хотел испытать что-то очень быстро в LINQPad, и я полагал, что это было бы слишком много потрудился, чтобы создать ядро ​​и загрузку в моих модулях, и я закончил писать это вручную:

var merger = new SimpleWorkflowInstanceMerger(
    new BitFactoryLog(typeof(SimpleWorkflowInstanceMerger).FullName), 
    new WorkflowAnswerRowUtil(
     new WorkflowFieldAnswerEntMapper(), 
     new ActivityFormFieldDisplayInfoEntMapper(), 
     new FieldEntMapper()), 
    new AnswerRowMergeInfoRepository()); 

В ретроспективе, было бы быстрее использовать структуру IoC, так как модули определяют почти все эти материалы по соглашению.

Проведя некоторое время на изучение ответов и комментариев по этому вопросу, я убежден, что люди, которые против использования контейнера IoC, не практикуют настоящую инъекцию зависимостей. Примеры, которые я видел, - это практики, которые обычно путают с инъекцией зависимостей. Некоторые люди жалуются на трудность «чтения» кода. Если все сделано правильно, подавляющее большинство вашего кода должно быть идентичным при использовании DI вручную, как при использовании контейнера IoC. Разница должна полностью соответствовать нескольким «точкам запуска» в приложении.

Другими словами, если вам не нравятся контейнеры IoC, вы, вероятно, не делаете инъекции зависимостей так, как это должно быть сделано.

Еще один момент: Инъекция зависимостей действительно не может быть выполнена вручную, если вы используете отражение где угодно. Хотя я ненавижу то, что отражается в навигации кода, вы должны признать, что есть определенные области, где этого действительно нельзя избежать. Например, ASP.NET MVC пытается создать экземпляр контроллера через отражение для каждого запроса. Для того, чтобы сделать инъекцию зависимостей вручную, вы должны сделать каждый контроллер «корневой контекст,» как так:

public class MyController : Controller 
{ 
    private readonly ISimpleWorkflowInstanceMerger _simpleMerger; 
    public MyController() 
    { 
     _simpleMerger = new SimpleWorkflowInstanceMerger(
      new BitFactoryLog(typeof(SimpleWorkflowInstanceMerger).FullName), 
      new WorkflowAnswerRowUtil(
       new WorkflowFieldAnswerEntMapper(), 
       new ActivityFormFieldDisplayInfoEntMapper(), 
       new FieldEntMapper()), 
      new AnswerRowMergeInfoRepository()) 
    } 
    ... 
} 

Теперь сравните это с разрешительными рамки DI, чтобы сделать это для вас:

public MyController : Controller 
{ 
    private readonly ISimpleWorkflowInstanceMerger _simpleMerger; 
    public MyController(ISimpleWorkflowInstanceMerger simpleMerger) 
    { 
     _simpleMerger = simpleMerger; 
    } 
    ... 
} 

Использование рамки DI, обратите внимание, что:

  • я могу модульного тестирования этого класса. Создав макет ISimpleWorkflowInstanceMerger, я могу проверить, что он используется так, как я ожидаю, без необходимости подключения к базе данных или чего-то еще.
  • Я использую гораздо меньше кода, и код гораздо проще читать.
  • Если изменения в зависимости от зависимости зависят, я не обязан вносить какие-либо изменения в контроллер. Это особенно приятно, если учесть, что несколько контроллеров могут использовать одни и те же зависимости.
  • Я никогда не ссылаюсь на классы из своего уровня данных. Мое веб-приложение может просто включать ссылку на проект, содержащий интерфейс ISimpleWorkflowInstanceMerger. Это позволяет мне разбить приложение на отдельные модули и поддерживать истинную многоуровневую архитектуру, что, в свою очередь, делает вещи намного более гибкими.

Типичное веб-приложение будет иметь довольно много контроллеров.Вся боль, выполняемая DI вручную в каждом контроллере, действительно будет складываться по мере роста вашего приложения. Если у вас есть приложение только с одним корнем контекста, который никогда не пытается создать экземпляр службы путем отражения, то это не такая большая проблема. Тем не менее, любое приложение, использующее Injection Dependency Injection, станет чрезвычайно дорогостоящим для управления, когда оно достигнет определенного размера, если вы не используете какую-либо структуру для управления графиком зависимости.

16

Я восстанавливающий наркоман МОК. В наши дни мне трудно обосновать использование IOC для DI в большинстве случаев. Контейнеры IOC жертвуют проверкой времени компиляции и предположительно взамен дают вам «легкую» настройку, сложное управление временем жизни и «на лету» обнаружение зависимостей во время выполнения. Я считаю, что потеря времени проверки компиляции и, в конечном итоге, магии времени/исключения, не стоит колоколов и свистов в подавляющем большинстве случаев. В крупных корпоративных приложениях им очень сложно следить за тем, что происходит.

Я не покупаю аргумент централизации, так как вы можете легко централизовать статическую настройку, используя абстрактную фабрику для своего приложения и религиозно откладывая создание объекта на абстрактную фабрику, т. Е. Делайте правильный DI.

Почему бы не сделать статическую волшебной свободной DI, как это:

interface IServiceA { } 
interface IServiceB { } 
class ServiceA : IServiceA { } 
class ServiceB : IServiceB { } 

class StubServiceA : IServiceA { } 
class StubServiceB : IServiceB { } 

interface IRoot { IMiddle Middle { get; set; } } 
interface IMiddle { ILeaf Leaf { get; set; } } 
interface ILeaf { } 

class Root : IRoot 
{ 
    public IMiddle Middle { get; set; } 

    public Root(IMiddle middle) 
    { 
     Middle = middle; 
    } 

} 

class Middle : IMiddle 
{ 
    public ILeaf Leaf { get; set; } 

    public Middle(ILeaf leaf) 
    { 
     Leaf = leaf; 
    } 
} 

class Leaf : ILeaf 
{ 
    IServiceA ServiceA { get; set; } 
    IServiceB ServiceB { get; set; } 

    public Leaf(IServiceA serviceA, IServiceB serviceB) 
    { 
     ServiceA = serviceA; 
     ServiceB = serviceB; 
    } 
} 


interface IApplicationFactory 
{ 
    IRoot CreateRoot(); 
} 

abstract class ApplicationAbstractFactory : IApplicationFactory 
{ 
    protected abstract IServiceA ServiceA { get; } 
    protected abstract IServiceB ServiceB { get; } 

    protected IMiddle CreateMiddle() 
    { 
     return new Middle(CreateLeaf()); 
    } 

    protected ILeaf CreateLeaf() 
    { 
     return new Leaf(ServiceA,ServiceB); 
    } 


    public IRoot CreateRoot() 
    { 
     return new Root(CreateMiddle()); 
    } 
} 

class ProductionApplication : ApplicationAbstractFactory 
{ 
    protected override IServiceA ServiceA 
    { 
     get { return new ServiceA(); } 
    } 

    protected override IServiceB ServiceB 
    { 
     get { return new ServiceB(); } 
    } 
} 

class FunctionalTestsApplication : ApplicationAbstractFactory 
{ 
    protected override IServiceA ServiceA 
    { 
     get { return new StubServiceA(); } 
    } 

    protected override IServiceB ServiceB 
    { 
     get { return new StubServiceB(); } 
    } 
} 


namespace ConsoleApplication5 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var factory = new ProductionApplication(); 
      var root = factory.CreateRoot(); 

     } 
    } 

    //[TestFixture] 
    class FunctionalTests 
    { 
     //[Test] 
     public void Test() 
     { 
      var factory = new FunctionalTestsApplication(); 
      var root = factory.CreateRoot(); 
     } 
    } 
} 

Конфигурация контейнера ваша абстрактный реализация фабрики, ваши регистраций реализации абстрактных членов. Если вам нужна новая синглтонная зависимость, просто добавьте еще одно абстрактное свойство на абстрактный завод. Если вам нужна переходная зависимость, просто добавьте другой метод и введите его как Func <>.

Преимущества:

  • Все настройки и создания объекта конфигурации централизованные.
  • Конфигурация - это только код
  • Проверка времени компиляции упрощает обслуживание, так как вы не можете забыть обновлять свои регистрационные данные.
  • Нет время выполнения отражения магии

Я рекомендую скептик, чтобы дать ему идти в следующий проект зеленого поля и честно спросить себя, в какой момент вам нужен контейнер. Легко включить в контейнер IOC позже, поскольку вы просто заменяете заводскую реализацию конфигурационным модулем IOC Container.

+0

Это не похоже на аргумент против IoC, а аргумент против _configurable_ IoC frameworks. Разве ваши фабрики здесь просто не сводятся к простым закодированным IoC? –

+0

Я думаю, когда речь зашла о плакате IoC, была использована контейнерная каркас IoC. Спасибо за оригинальную запись, это помогает убедить меня пойти без рамки. Так что, если он настраивается в тестах и ​​в производственном коде, в чем преимущество «настраиваемой» структуры? – huggie

+0

Из моего понимания терминологии Inversion Of Control означает поиск зависимостей во время выполнения. Итак, вы можете сказать, что завод в основном представляет собой жесткий или статический контейнер, но это не контейнер IOC. Типы разрешаются во время компиляции. Это аргумент против использования настраиваемых фреймворков, которые используют словарный поиск для разрешения типов во время выполнения. – Maxm007

1

Честно говоря, я не вижу там много случаев, когда нужны контейнеры IoC, и большую часть времени они просто добавляют ненужную сложность.

Если вы используете его только для упрощения построения объекта, я должен спросить, вы создаете экземпляр этого объекта в нескольких местах? Будет ли синглтон не соответствовать вашим потребностям? Вы меняете конфигурацию во время выполнения? (Переключение типов источников данных и т. Д.).

Если да, то вам может понадобиться контейнер IoC. Если нет, то вы просто перемещаете инициализацию в сторону, где разработчик может легко ее увидеть.

Кто сказал, что интерфейс лучше, чем наследование? Скажем, вы тестируете Сервис. Почему бы не использовать конструктор DI и создать mocks зависимостей с использованием наследования? Большинство сервисов, которые я использую, имеют только несколько зависимостей. Тестирование модуля таким образом предотвращает поддержание тонны бесполезных интерфейсов и означает, что вы не имеете, чтобы использовать Resharper для быстрого поиска объявления метода.

Я считаю, что для большинства реализаций, говоря, что IoC Containers удаляет ненужный код, это миф.

Во-первых, в первую очередь создается контейнер. Затем вам необходимо определить каждый объект, который необходимо инициализировать. Таким образом, вы не сохраняете код при инициализации, вы его перемещаете (если ваш объект не используется более одного раза. Лучше ли он как Singleton?). Затем для каждого объекта, который вы инициализировали таким образом, вам необходимо создать и поддерживать интерфейс.

У кого-нибудь есть мысли по этому поводу?

+0

Даже для небольших проектов размещение конфигурации в XML делает ее настолько чище и модульной, и в первый раз делает код повторно используемым (поскольку он больше не загрязнен клеем). Для правильных программных продуктов вы можете настроить или обменять, например, «ShippingCostCalculator» или «ProductUIPresentation» или любую другую стратегию/реализацию, в той же самой кодовой базе, путем развертывания только одного измененного XML-файла. –

+0

Если это реализовано волей-неволей, как общая практика, я думаю, вы добавляете больше сложности, не меньше. Когда вам нужно что-то менять во время выполнения, они великолепны, но зачем добавлять обфускацию? Зачем использовать дополнительные интерфейсы для вещей, которые никогда не будут отключены? Я не говорю, что я не использую IoC для тестирования. Во что бы то ни стало, используйте инъекцию зависимости свойства или даже конструктора. Вам нужно использовать интерфейс? Почему бы не подклассировать тестовые объекты? Разве это не было бы чище? – Fred

+0

Вам совсем не нужны интерфейсы, чтобы выполнить конфигурацию XML/IoC. Я нашел большие улучшения в ясности в небольшом проекте с только ~ 8 страницами и 5 или 6 сервисами. Там _less obfuscation_, поскольку службам и контроллерам больше не нужен код клея. –

2

Итак, прошло почти три года, а?

  1. 50% тех, кто высказался в поддержку IoC-фреймворков, не понимают разницы между IoC и IoC Framework. Я сомневаюсь, что они знают, что вы можете написать код без развертывания на сервер приложений

  2. Если мы возьмем наиболее популярные рамки Java Spring, это конфигурация IoC перемещается из Xml в код и выглядеть следующим образом

`@Configuration общественного класса AppConfig {

public @Bean TransferService transferService() { 
    return new TransferServiceImpl(accountRepository()); 
} 

public @Bean AccountRepository accountRepository() { 
    return new InMemoryAccountRepository(); 
} 

} ` И мы нужны рамки, чтобы сделать это, почему именно?

1

Вам понадобится контейнер IoC, если вам необходимо централизовать конфигурацию ваших зависимостей, чтобы их можно было легко поменять на массу. Это имеет наибольший смысл в TDD, где меняются многие зависимости, но там, где существует небольшая взаимозависимость между зависимостями. Это делается за счет того, что в некоторой степени запутывает поток контроля над конструкцией объекта, поэтому важно иметь хорошо организованную и обоснованную документацию. Также хорошо иметь повод сделать это, в противном случае это просто abstraction gold-plating. Я видел, как это делалось так плохо, что оно было перетащено в эквивалент инструкции goto для конструкторов.

1

Here. Проект называется IOC-with-Ninject. Вы можете загрузить и запустить его с помощью Visual Studio. В этом примере используется Ninject, но ВСЕ «новые» операторы находятся в одном месте, и вы можете полностью изменить, как работает ваше приложение, изменив используемый модуль привязки. Пример настроен таким образом, что вы можете привязываться к издевавшейся версии служб или реальной версии. В небольших проектах, которые могут не иметь значения, но в крупных проектах это большое дело.

Просто чтобы быть ясно, преимущество, как я их вижу: 1) ВСЕХновых заявления в одном месте в корне коды. 2) Полностью пересчет кода с одним изменением. 3) Дополнительные очки за «классный фактор», потому что это ... хорошо: круто. : Р

1

Я попытаюсь найти причину, по которой МОК может не понравиться с моей точки зрения.

Как и все остальное, контейнер IOC (или, как сказал Эйнштейн I = OC^2), представляет собой концепцию, которую вы должны решить самостоятельно, если вам это нужно или нет в вашем коде. Недавний модный протест в отношении МОК - это только мода. Не поддавайтесь моде, это прежде всего. Есть множество концепций, которые вы можете реализовать в своем коде. Прежде всего, я использую инъекцию зависимостей, так как я начал программировать, и узнал сам термин, когда он был популяризирован под этим именем. Контроль зависимостей - очень старая тема, и до сих пор она была рассмотрена триллионами способов, в зависимости от того, что отделялось от чего. Развязать все от всего - это вздор. Проблема с контейнером IOC заключается в том, что он пытается быть таким же полезным, как Entity Framework или NHibernate. При написании объектно-реляционного картографа просто необходимо, как только вам придется связывать любую базу данных с вашей системой, контейнер IOC не всегда необходим. Поэтому, когда контейнер МОК полезен:

  1. Когда у Вас есть ситуация со многими зависимостями, которые вы хотите организовать
  2. Если вы не заботитесь о сцеплении код с третьей стороной продуктом
  3. Когда ваши разработчики хотят научиться работать с новым инструментом

1: Это не так часто, что у вас так много зависимостей в вашем коде или что вы знаете о них в раннем дизайне. Абстрактное мышление полезно при абстрактном мышлении.

2: Совмещение кода с сторонним кодом является проблемой HuGe. Я работал с кодом, которому уже 10+ лет, и в то время это были фантастические и продвинутые концепции ATL, COM, COM + и т. Д. Теперь с этим кодом вы ничего не можете сделать. Я говорю, что продвинутая концепция дает очевидное преимущество, но это отменяется в долгосрочной перспективе с использованием самого устаревшего преимущества. Он просто сделал все это дороже.

3: Разработка программного обеспечения достаточно трудна. Вы можете расширить его до неузнаваемых уровней, если вы позволите некоторым расширенным понятиям обрезать ваш код. Проблема с IOC2. Хотя это развязка зависимостей, она также развязывает логический поток. Представьте, что вы нашли ошибку, и вам нужно установить перерыв, чтобы изучить ситуацию. IOC2, как и любая другая передовая концепция, затрудняет это. Исправление ошибки внутри концепции сложнее, чем исправление ошибки в более понятном коде, потому что, когда вы исправляете ошибку, концепция должна выполняться снова. (Чтобы дать вам пример, C++ .NET постоянно меняет синтаксис настолько, что вам нужно много думать, прежде чем реорганизовать какую-то более старую версию .NET.) Так в чем же проблема с IOC? Проблема заключается в разрешении зависимостей. Логика разрешения обычно скрыта в самой IOC2, написанной, может быть, необычным образом, что вам нужно учиться и поддерживать. Будет ли ваш сторонний продукт через 5 лет? Microsoft не было.

«Мы знаем, как синдром, написанный повсюду в отношении IOC2. Это похоже на тестирование автоматизации. Причудливый термин и идеальное решение на первый взгляд, вы просто ставите все свои тесты на ночь и видите результаты утром. Очень больно объяснять компании после компании, что на самом деле означает автоматическое тестирование. Автоматическое тестирование - это, безусловно, не быстрый способ уменьшить количество ошибок, которые вы можете ввести за одну ночь, чтобы повысить качество вашего продукта. Но мода делает это понятие досадно доминирующим. IOC2 страдает одним и тем же синдромом. Считается, что вам нужно реализовать его, чтобы ваше программное обеспечение было хорошим. Последнее интервью EvErY меня спросили, реализую ли я IOC2 и автоматизацию. Это признак моды: у компании была часть кода, написанная в MFC, которую они не оставят.

Вам необходимо изучить IOC2 как любую другую концепцию программного обеспечения. Решение, если IOC2 необходимо использовать, входит в состав команды и компании. Однако, прежде чем решение будет принято, следует упомянуть хотя бы ВСЕ приведенные выше аргументы. Только если вы видите, что плюсовая сторона перевешивает негативную сторону, вы можете принять положительное решение.

Нет ничего плохого в IOC2, за исключением того, что он решает только проблемы, которые он решает, и вводит проблемы, которые он представляет. Ничего больше. Однако идти против моды очень сложно, у них есть пот, последователи чего-либо. Странно, как никто из них не существует, когда проблема с их причудой становится очевидной. Многие концепции в индустрии программного обеспечения защищены, потому что они создают прибыль, книги написаны, проводятся конференции, выпускаются новые продукты. Это мода, обычно недолговечная. Как только люди находят что-то еще, они полностью отказываются от него. IOC2 полезен, но он показывает те же признаки, что и многие другие исчезнувшие концепции, которые я видел. Я не знаю, выживет ли он. Для этого нет правила. Вы думаете, что если это полезно, оно выживет. Нет, это не так. Одной большой богатой компании достаточно, и концепция может умереть в течение нескольких недель. Посмотрим. NHibernate выжил, EF занял второе место. Возможно, IOC2 тоже выживет. Не забывайте, что большинство концепций в разработке программного обеспечения ничего особенного не имеют, они очень логичны, просты и очевидны, и иногда сложнее запомнить текущее соглашение об именах, чем понимать саму концепцию. Знает ли IOC2 разработчика лучше разработчика? Нет, потому что, если разработчику не удалось придумать концепцию, похожую по характеру на IOC2, то ему или ей будет трудно понять, какая проблема IOC2 решает, используя ее будет выглядеть искусственно, и он или она может начать использовать ее ради того, чтобы быть каким-то политически правильным.

0

Я понимаю, что это довольно старое сообщение, но оно все еще достаточно разумно, и я подумал, что внес бы пару моментов, которые еще не упоминались в других ответах.

Я скажу, что я согласен с преимуществами инъекции зависимостей, но я предпочитаю самостоятельно создавать и управлять объектами, используя шаблон, который не похож на шаблон, описанный Maxm007 в его ответе. Я обнаружил две основные проблемы с использованием сторонних контейнеров:

1) Наличие библиотеки сторонних разработчиков для управления временем жизни ваших объектов «автоматически» может принести неожиданные результаты. Мы обнаружили, что особенно в крупных проектах у вас может быть гораздо больше копий объекта, чем вы ожидаете, и больше, чем если бы вы вручную управляли жизненными циклами. Я уверен, что это зависит от используемой структуры, но проблема существует, тем не менее. Это также может быть проблематичным, если ваш объект содержит ресурсы, подключения к данным и т. Д., Так как объект может жить дольше, чем вы ожидаете. Таким образом, контейнеры IoC неизбежно увеличивают использование ресурсов и объем памяти приложения.

2) Контейнеры IoC, на мой взгляд, являются формой программирования «черного ящика». Я обнаружил, что, в частности, наши менее опытные разработчики склонны злоупотреблять ими. Это позволяет программисту не думать о том, как объекты должны относиться друг к другу или как их отделять, потому что он предоставляет им механизм, в котором они могут просто захватить любой объект, который они хотят из воздуха. Например, может быть хорошая причина дизайна, что ObjectA никогда не должен знать об ObjectB напрямую, но вместо создания фабрики или моста или локатора сервисов неопытный программист просто скажет: «Нет проблем, я просто возьму ObjectB из контейнера IoC ». Это может привести к увеличению связи объектов, что, как предполагается, предотвратит IoC.

Смежные вопросы