Зачем мне нужен контейнер IoC, а не простой код DI?

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

Я играл с .NET-контейнерами, такими как StructureMap, NInject, Unity и Funq. Я до сих пор не понимаю, как контейнер IoC может улучшить / улучшить мой код.

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

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


person Community    schedule 16.05.2009    source источник
comment
Хороший вопрос. Я отвечаю на это в комментариях, так как я новичок в идее МОК. Это похоже на идею plug and play компонентов и слабой связи. Потребуется ли вам использовать какой-либо другой компонент вместо текущего. Использование IOC заключается в подготовке кода для такого изменения, если оно возникнет IMO.   -  person shahkalpeshp    schedule 16.05.2009
comment
@shahkalpesh, но я могу добиться слабой связи с помощью простого DI. Однако я понимаю вашу точку зрения, если я использую файл конфигурации. Однако я не уверен, что мне нравится использовать файл конфигурации. Файлы конфигурации очень многословны, возникают трудности с рефакторингом и переключением между несколькими файлами.   -  person Vadim    schedule 16.05.2009
comment
просто добавляю комментарий, поскольку кажется, что вы ищете причины для использования в основном IoC; но о вашей проблеме нужно сказать кое-что еще. Вы не можете написать свой код на уровне худшего человека в вашей команде или из страха, что он не захочет учиться. Вы несете ответственность не только за то, чтобы быть профессионалом, но и за свое будущее, чтобы расти, и ваша команда не должна вас сдерживать.   -  person Kevin Sheffield    schedule 07.10.2009
comment
@Kevin, вообще-то мы используем IoC. Было не так сложно научить всех работать с IoC.   -  person Vadim    schedule 07.10.2009
comment
@ Вадим, приятно слышать. Думаю, по стандартам Джоэла ваша команда полна гениев, и я вам завидую, ха!   -  person Kevin Sheffield    schedule 07.10.2009
comment
+1 @Vadim ... действительно очень полезный пост   -  person Kyaw Thurein    schedule 18.01.2011
comment
Понятия не имею, почему модераторы закрывают полезные вопросы, за которые проголосовали массово. Возможно, в этом случае Уилл не понимает вопроса или не понимает, для чего люди используют stackexchange? Если он не подходит для формата вопросов и ответов stackexchange, то, возможно, подумайте, что ваша политика неверна, а не все эти сотни полезных вопросов с сотнями голосов за и полезные ответы за них.   -  person NickG    schedule 10.08.2012


Ответы (30)


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

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());

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

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

Некоторые другие интересные варианты использования инструмента IoC для АОП:

  • Декларативные и вложенные транзакции базы данных
  • Декларативная и вложенная единица работы
  • логирование
  • Условия до / после (Дизайн по контракту)
person Community    schedule 07.10.2009
comment
Отличное дополнение. Я часто занимаюсь сантехникой для объекта. Теперь я открою свой разум для IoC и посмотрю, чем это можно объяснить. - person Pierre-Alain Vigeant; 07.10.2009
comment
Кроме того, какой инструмент IoC вы тоже имеете в виду? - person Pierre-Alain Vigeant; 07.10.2009
comment
К сожалению, вы забыли сделать все свойства виртуальными, и это не сработало. Вам тоже нужно было потратить время на отладку этого кражи у вашего клиента? (Приносим извинения, если вы не используете DynamicProxy .: P) - person Thom; 07.10.2009
comment
На самом деле мы используем IoC. Это было не так сложно, как я думал, рассказать всем о IoC. - person Vadim; 07.10.2009
comment
Поистине единственный способ написать поддерживаемый код. - person Ryan Emerle; 07.10.2009
comment
Вы жертвуете МНОГО ясности, используя оболочку INotifyPropertyChanged. Если у вас уходит больше нескольких минут на то, чтобы написать эту сантехнику для начала, значит, вы не в том деле. Когда речь идет о многословности вашего кода, меньше не значит больше! - person overstood; 07.10.2009
comment
@overloaded - полностью не согласен. Во-первых, какое значение имеет ясность в этом примере? Ближайший к потребителю. Потребитель явно запрашивает INotifyPropertyChanged. Тот факт, что мы можем создать этот тип кода с помощью генерации микрокода или макроса, не означает, что писать его - хорошая идея. Этот мусор INotifyPropertyChanged является просто рутинным, рутинным, бессмысленным и фактически снижает удобочитаемость рассматриваемого класса. - person Ben Scheirman; 08.10.2009
comment
Меня интересует, какой инструмент знает, как автоматически вводить код для работы в качестве NotifyPropertyChangedWrapper (), хотя ваш пример создан так, чтобы быть особенно плохим - если бы вы использовали Observable-оболочки вокруг каждого свойства, вы могли бы сделать код значительно чище без используя контейнер IoC (или что-то еще, что есть NotifyPropertyChangedWrapper ()). - person Jamie Love; 08.10.2009
comment
Джейми - настоящая работа обычно выполняется чем-то вроде DynamicProxy, которое позволяет вам легко перехватывать вызовы (виртуальных или интерфейсных) членов ваших объектов. Это не имеет ничего общего с IoC - на самом деле, в приведенном выше примере мы все равно говорим об объекте, поэтому вы никогда не сможете разрешить это из своего контейнера. Вам придется возиться со своим ORM, который полностью отдельный. Я не хочу показаться анти-IoC - я использую Castle и множество настраиваемых средств в моем текущем проекте, но приведенный выше пример плохой (который не работает так, как написано или как описано). - person Thom; 08.10.2009
comment
Честно говоря, в моем комментарии рассматривалась первая половина вашего ответа перед редактированием. Вы немного пошли по пути с оболочкой NotifyPropertyChanged (это не частый случай, хотя, по общему признанию, круто). - person Anderson Imes; 08.10.2009
comment
@Jamie, @Thom Я не думаю, что приведенный выше пример Бена каким-либо образом должен был быть полной реализацией. Тем не менее, мне было бы любопытно увидеть вашу реализацию Observable-оболочек вокруг каждого свойства, которая не похожа на типичную реализацию INotifyPropertyChanged. - person ; 09.10.2009
comment
Отмечено вниз, потому что вы путаете шаблон внедрения зависимостей и шаблон Service Locator. Первое предназначено для использования вместо второго. Например. объект (или даже вся система) никогда не должен вызывать Resolve (...) для получения экземпляра IShippingService. Объекты, которым требуется IShippingService, должны получить ссылку на экземпляр, который они должны использовать при создании, а некоторый более высокий уровень отвечает за соединение двух объектов вместе. - person Nat; 26.10.2009
comment
@Nat: Я не путаю их. Я демонстрирую мощь инструмента IoC. В конце концов вы должны попросить у контейнера объект, и в идеале это происходит на переднем плане, а последующие инъекции происходят за вас. - person Ben Scheirman; 03.11.2009
comment
@Nat: См. Мой комментарий по этой теме в следующем ответе. - person Ben Scheirman; 03.11.2009
comment
Что бы это ни было (IoC, DynamicProxy, AOP или черная магия), может ли кто-нибудь связать меня с конкретной статьей / конкретной документацией в структуре, которая предоставляет более подробную информацию для достижения этого? - person fostandy; 19.05.2010
comment
Бен - Хотя я согласен с вашими комментариями по IoC / DI, я думаю, что этот пример - var bindingFriendlyInstance = IoC.Resolve ‹Customer› (new NotifyPropertyChangedWrapper ()); кажется совершенно неправильным. Я не вижу никакого сценария, в котором ваш контейнер IoC мог бы вернуть объект Customer с помощью INotify .., реализованного без того, чтобы что-то еще объявляло мусор Как, черт возьми, вы бы на самом деле это реализовали? - person Chris Webb; 24.11.2010
comment
Я должен согласиться с Крисом Уэббом, как NotifyPropertyChangedWrapper выглядит ?? - person Ropstah; 13.02.2011
comment
Меня смущает этот ответ. Ответ здесь на SO, который я не могу найти, говорит, что объекты никогда не должны создаваться DIC. Этот говорит, что ваше приложение должно быть разделено на конструкцию и выполнение часть, и DIC никогда не должен отображаться в исполнительной части, что делает невозможным его использование для создания объекта. - person K. Norbert; 17.03.2011
comment
IoC! = АОП. IoC направлен на устранение жестко зашитых зависимостей между объектами / службами, в то время как АОП нацелено на разделение проблем в хорошо инкапсулированных модулях и автоматическое устранение всех этих проблем. Первое можно использовать для выполнения второго, но есть и другие (вероятно, лучшие) альтернативы, такие как предварительная обработка или генерация динамического кода. На мой взгляд, если вы решите использовать контейнер IoC, потому что он позволяет вам выполнять АОП, вы делаете неправильный выбор: для этого есть лучшие инструменты (см. Многочисленные фреймворки АОП, такие как PostSharp, AspectC ++, AspectJ и т. Д. .). - person Luc Touraille; 05.04.2012
comment
@ChrisWebb Кто-то очень услужливо задал это как новый вопрос SO и получил полезный ответьте, если вам все еще интересно. - person Jordan Gray; 14.08.2012
comment
@Ben Scheirman Ваш первый пример плохой - вы пропустили пять строк регистрации. - person Dave Hillier; 27.09.2013
comment
IOC и AOP не идентичны, нет, но они очень хорошо идут рука об руку. Castle Windsor дает вам и то, и другое. Вот пример того, как вы можете использовать его для реализации INotifyPropertyChanged в умный способ. Мы успешно использовали это в нашем фреймворке приложения на работе, в настоящее время расширяет возможности около 50? или около того приложений. Я полностью согласен с тем, кто написал, что классы без большого количества погружений намного легче читать и поддерживать. - person Per Lundberg; 17.10.2013
comment
Надеюсь, Бен ушел за 4 года и теперь смущен этим ответом. 400+ голосов за атаку на двух плохо сконструированных соломенных человечков - ужасное обвинение в том, насколько плохим может быть источник информации SO. - person David Arno; 12.11.2013
comment
-1, это пример того, как не использовать IOC. - person Jimmy; 06.02.2014
comment
Ваш второй пример, похоже, совершенно не связан с МОК. Я вообще не использую IOC (придерживаясь стандартного DI), но действительно использую AOP через PostSharp и могу полностью реализовать INotifyProperty через переплетение аспектов, добавив атрибут поверх моего класса. Поскольку этот вопрос касается того, что IOC приносит на стол и что вы можете получить от этого, чего не могли бы получить в противном случае, я должен сделать вывод, что либо вы не понимаете, что такое АОП и чем он отличается от IOC, либо вы лукавите. - person Asad Saeeduddin; 20.03.2014

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

Я лично недоумеваю, как сообщество IoC восприняло красивую, элегантную статью Мартина Фаулера и превратил его в кучу сложных фреймворков, обычно с руководствами на 200–300 страниц.

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

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

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

person Community    schedule 16.05.2009
comment
Если можно так выразиться, это похоже на разный взгляд на мир у разных людей. Люди, которые используют IOC, похожи на идеологов, желающих, чтобы мир пошел по их стопам, и есть другие, такие как я (и другие разработчики), которые застряли между идеологией и реальностью;) - person shahkalpeshp; 17.05.2009
comment
Не могу с этим согласиться. Начал изучать использование инфраструктуры DI (StructureMap), которая утверждает, что это самый старый контейнер IoC. Сложность была ошеломляющей, учитывая то, что я хотел. Вместо этого я пишу свой очень простой локатор услуг. Возможно, один из других контейнеров IoC имел бы больше смысла, но я действительно не вижу в этом смысла и у меня нет досуга, чтобы потратить несколько дней на выяснение, как использовать что-то, что усложнит чтение кода. - person eesh; 29.05.2009
comment
Мартин Фаулер, будучи великим писателем, никоим образом не изобретал IoC. - person Nicholas Blumhardt; 16.08.2009
comment
Я думаю, ты немного перепутал свои факты, Джоэл. Сначала появились IoC и контейнеры, затем - трактат Мартина, а не наоборот. - person Glenn Block; 18.08.2009
comment
shahkalpesh С каким контейнером IoC вы работали? - person Glenn Block; 18.08.2009
comment
eesh большинство контейнеров позволяют очень быстро приступить к работе. С помощью autofac, structure map, unity, ninject и т. Д. Вы сможете запустить контейнер примерно за 5 минут. Да, у них есть расширенные функции, но они вам не нужны, чтобы начать работу. - person Glenn Block; 18.08.2009
comment
Как это: ninject.codeplex.com/Wiki / считается, что ракетостроение выше меня. - person Sam Saffron; 19.09.2009
comment
Раньше я использовал структурную карту и Unity. Вы можете сделать базовое очень просто (несколько строк кода, прочитать их ответы на часто задаваемые вопросы), но если вы попытаетесь втиснуть его в слишком много ситуаций, это быстро станет сложным. - person Beep beep; 19.09.2009
comment
Я фанат контейнеров IoC, но никоим образом не думаю, что их «легко достать» (концепции довольно абстрактны и затрагивают суть разработки программного обеспечения) ... Также я думаю, что ответ Джоэла побудит людей отклонить важные идеи, лежащие в основе IoC, отсюда и мой голос против. - person Jack Ukleja; 20.09.2009
comment
Кроме того, если кто-то пишет тестируемый код, следуя SRP и т. Д. (Что, как я думаю, большинство людей согласны с этим, это хорошо), ваш класс в основном всегда заканчивается множеством зависимостей интерфейсов. Я спрашиваю: без фреймворка IoC, как вы, черт возьми, подключаете все свои классы? - person Jack Ukleja; 20.09.2009
comment
Откровенно говоря, следовать IoC без контейнера намного сложнее и отнимать много времени, чем чтение 200-страничного руководства. Не говоря уже о том, что контейнеры появились до статьи г-на Фаулера и являются неотъемлемой частью паттерна проектирования. Итак, если г-н Спольски хотел заявить, что IoC был чрезмерно сложным, нам, возможно, пришлось бы согласиться, чтобы не согласиться, но поскольку он сказал не это ... он просто ошибся. - person wekempf; 07.10.2009
comment
Джоэл. Я думал так же, как ты. Затем я буквально и серьезно потратил пять минут на то, чтобы выяснить, как запустить самую простую настройку, и был поражен правилом 80/20 в действии. Это делает код намного чище, особенно в простых случаях. - person Justin Bozonier; 07.10.2009
comment
Я программировал меньше двух лет, прочитал вики Ninject и понял. С тех пор я использую DI во многих местах. Ты это видел? Менее двух лет и чтение нескольких страниц вики. Я не волшебник или что-то в этом роде. Я не считаю себя гением, но мне это было легко понять. Я не могу себе представить, чтобы кто-то действительно понимал объектно-ориентированный объект, не будучи в состоянии понять это. Кроме того, какие руководства на 200-300 страниц вы имеете в виду? Я таких никогда не видел. Все контейнеры IoC, которые я использовал, довольно короткие и по существу. - person J.R. Garcia; 07.10.2009
comment
Итак, если вы не используете контейнеры IoC, это потому, что вы недостаточно умны, чтобы их понимать, но если вы используете контейнеры IoC (и любите каждую секунду), это потому, что вы слишком умны? - person Anderson Imes; 07.10.2009
comment
@ Joel-spolsky Я не понимаю, почему вы думаете, что это затрудняет чтение кода. Код на самом деле проще для понимания. Все ваши зависимости просто вводятся через конструкторы. Никакого отслеживания зависимостей не требуется. Для настройки требуется около 2-3 строк кода, в зависимости от того, сколько элементов вам нужно создать. - person Micah; 07.10.2009
comment
Я не знаю, почему вы, ребята, допрашиваете Джоэла. Он знает, что творится у нас в головах, чувак похож на Деда Мороза или что-то в этом роде. Он знает, что мы не можем понять IoC и даже больше, чем мы можем надеть штаны утром без посторонней помощи. Спасибо, Джоэл, что напомнил мне, какой я тупой, я был слишком самовлюбленным. - person Kevin Sheffield; 07.10.2009
comment
Джоэл - Полагаю, вы какое-то время не смотрели на контейнеры IoC, потому что за последние пару лет определенно прошел переломный момент. Теперь их легко настроить, в основном из-за условностей. DI - это хорошо; упростить внедрение и поддержку передовой практики. Зачем передавать конкретные реализации вашего кода, если сторонняя библиотека может сделать это за вас? Контейнер IoC будет: управлять всем графом; без необходимости перебивать ваши классы с помощью poormans DI ctors; сокращение строк кода и; централизация разрешения зависимостей в одном кратком месте вашей базы кода. - person Ed Blackburn; 07.10.2009
comment
Джоэл. Ваше заявление о том, что основным преимуществом IoC является замена реализаций для тестирования, показывает, что вы не понимаете IoC. IoC - это разделение задач и освобождение вас от необходимости переписывать все цепочки создания экземпляров, когда вы хотите добавить / удалить зависимость. Не говоря уже о многих других преимуществах - person Arne Claassen; 07.10.2009
comment
Я действительно не понимаю, как меня убедили прийти на StackOverflow DevDays - person CodeClimber; 07.10.2009
comment
Мне нужно сделать футболку с надписью I Heart VBA для дней разработки - person user7375; 07.10.2009
comment
Вау ... Блин, поговорим об ответной реакции. Думаю, это какой-то эксперимент, как не идти против толпы. Честно говоря, я не занимался полной разработкой слишком долго (почти 3 года), и я использовал 3 разных контейнера .Net IoC. Я не претендую на понимание всего, что они делают. Но я знаю, что они упростили мою разработку. Точно так же я использую SQL Server. Но я не буду претендовать на понимание всех тонкостей современной системы РСУБД. - person Min; 07.10.2009
comment
В защиту Джоэла, DI и IoC могут быть очень трудными для понимания в сборке Z80 или при использовании шаблонов с COM в многопоточном коде. - person ScottKoon; 07.10.2009
comment
+1 хорошо написано и продумано. Я думаю, что многие люди не понимают, что добавление фреймворка или чего-то подобного для волшебной обработки чего-либо автоматически добавляет сложности и ограничения к системе. Иногда это того стоит, но часто что-то упускается из виду, и энтропия выделяется в код, пытаясь исправить проблему, вызванную ограничениями. Это может сэкономить время заранее, но люди должны понимать, что попытки решить какую-то неясную проблему могут стоить в 100 раз больше, лишь немногие люди действительно обладают достаточными знаниями для решения. - person kemiller2002; 07.10.2009
comment
@Ryan Emerle: Мне кажется, что есть разница между изучением IoC и верой в то, что фреймворк IoC должен использоваться повсеместно. - person Steven Huwig; 07.10.2009
comment
Я полностью согласен с Джоэлом ... похоже, здесь ужасно много пупка задевает, когда более простое решение смотрит вам прямо в лицо. Люди склонны забывать о принципе KISS, и это тот случай, когда его очень необходимо применить. - person Craig; 07.10.2009
comment
IOC прекрасен, когда все сделано правильно, но действительно ужасно, когда кто-то портит его, и в конце концов кто-то испортит. Он также может запутать, что именно происходит, с помощью небольшого количества кода. ИМХО всегда лучше, если вы можете посмотреть немного кода и понять, что происходит за несколько секунд, не копаясь в остальной части источника. - person overstood; 07.10.2009
comment
У меня есть соблазн поставить +1 только за то, что я агрессивно выражаю мнение меньшинства, но я воздержусь - я думаю, вы частично правы в том, что контейнеры IOC могут усложнять простые вещи и затруднять отслеживание кода (потому что так много из пути кода становятся косвенными), но есть и другие преимущества, помимо упомянутых вами, что обеспечивает удобный способ создания шаблонов для ресурсов приложения. Тебе придется где-нибудь с этим разобраться. Я также не думаю, что они слишком сложные, но опять же, я работаю где-то, где весь IOC закодирован в обратном порядке (!), Так что, возможно, вам не стоит верить мне на слово. - person Steve B.; 08.10.2009
comment
Вы сделали отличный выбор для небольших приложений. Однако сложность использования контейнера IoC преодолима в средних и крупных проектах и ​​окупается за счет стоимости. - person Robert Venables; 08.10.2009
comment
Есть несколько комментаторов, которые поддерживают аргумент Джоэла, цитируя KISS. Эти люди не понимают, что использование контейнера IoC - это путь KISS. KISS означает «держать это просто, глупо, а не начинать с простого, кончить беспорядком, глупо» (SOSEUWMS). Контейнер IoC помогает поддерживать простоту приложения по мере его роста с течением времени. Я уверен, что Джоэл является поклонником SOSEUWMS, потому что он помогает поддерживать высокий спрос на средства отслеживания ошибок. - person Paul Batum; 08.10.2009
comment
Дело не в том, что мне трудно поверить в то, что есть люди, которые не понимают IoC, а в том, что мне трудно поверить в то, что есть люди, которые не будут пытаться понять. По правде говоря, это не так уж и сложно. Я думаю, что самая большая проблема в том, что название звучит устрашающе. - person KevDog; 08.10.2009
comment
Я не уверен, серьезно ли вы попробовали StructureMap. Пожалуйста, посмотрите одно из видео Роба Коннери, вы можете начать использовать его через 10 минут. Без шуток.!!! - person Ajay; 09.10.2009
comment
Как и во многих других ситуациях, ваша попытка защитить разработчиков от сильных идей заканчивается покровительством им и обесцениванием их способностей. Чтобы закрепить свою точку зрения, вы должны предоставить пример контейнера IoC с 200-страничным руководством - я просто не верю, что он есть! Что делает вашу противоположную риторику гораздо менее приятной. Чтобы практиковать IoC / DI, нужно изучить проблемы, решаемые этими методами. С таким пониманием вы можете использовать любые инструменты или ничего. Без него неважно, какой инструмент вы используете. - person Bryan Watts; 09.10.2009
comment
@KevDog: Я полностью согласен с проблемой имени. Контейнер для внедрения зависимостей полностью похож на что-то, изобретенное далеком. - person Bill Karwin; 10.10.2009
comment
Я использую контейнер IOC, и я не умный. - person Miyagi Coder; 19.10.2009
comment
+1 для проверки работоспособности, чтобы уменьшить сложность кода - person alchemical; 22.01.2010
comment
Я предполагаю, что Джоэл говорит о чем-то вроде Spring, а не о Guice. Guice очень прост и не требует более 15 минут знакомства. С другой стороны, Spring - более сложный (но более универсальный) зверь. - person ponzao; 19.05.2010
comment
Вау, самый спорный пост ... только потому, что Джоэл осмелился предположить, что IoC - это не грааль разработки для всех и каждого. Честно говоря, хватит уже религиозных войн! Даже если (большое, если) IoC - лучшее решение со времен нарезанного масла, даже любой полуприличный программист с более чем парой недель реального опыта за пределами академических кругов не может поверить, что это лучшее решение во всех - или даже в большинстве - ситуаций. . - person AviD; 13.06.2010
comment
С другой стороны, я считаю себя довольно умен, и хотя я потратил время на исследования и достаточно опыта, чтобы разобраться в IoC, я все равно ненавижу это. С страстью. Но это может быть только потому, что я трачу большую часть своего времени на чтение кода, а не просто на создание кода только для записи .... именно здесь IoC действительно сияет, пишу немного кода, а затем объединяю их и рекомбинировать по-другому во время настройки. С другой стороны, удобочитаемость кода сильно страдает от IoC. - person AviD; 13.06.2010
comment
Если вы имеете дело с подключением сотен + компонентов и хотите централизованный способ управления зависимостями, контейнер IoC значительно упрощает жизнь. Я скептически относился к использованию контейнера, потому что не видел преимуществ. Теперь я убежден, что это полезные части комплекта. Мы меняем огромные участки построения графа объектов через конфигурацию и повторно используем наши модули в разных контекстах (это то, что мы делаем активно, а не просто спекулятивная мечта). Компромисс - незнание новой концепции и принесение в жертву некоторой безопасности времени компиляции. - person Mark Simpson; 18.06.2010
comment
@Joel, знаете ли вы, что это самый противоречивый ответ на сайте? :) data.stackexchange.com/stackoverflow/ s / 87 / - person Trufa; 14.12.2010
comment
@AviD: На самом деле IoC сияет в модульное тестирование - я сомневаюсь, что использовал бы его, если бы мог тестировать без него, но поскольку DI + mocking в значительной степени только хочет тестировать классы изолированно, и это выгода определенно на 100% стоит дополнительных усилий, пока мне придется придерживаться этого. - person BlueRaja - Danny Pflughoeft; 18.02.2011
comment
В этом ответе есть доля правды, поскольку авторы большинства статей о DI, которые я видел, похоже, совершенно неспособны объяснить концепцию, прибегая к куче жаргона. Они пишут объяснения DI для людей, которые уже знают DI. Они не пишут для людей, которые не знают DI и которым нужно учиться. - person Ryan Lundy; 15.03.2011
comment
@Kyralessa: см. github.com/ninject/ninject/wiki/Dependency- Инъекция вручную - person BlueRaja - Danny Pflughoeft; 17.06.2011
comment
Ответ доказывает, что почти половина участников сообщества считает, что кнопка «против» не согласна, а не «Этот ответ бесполезен». Я ненавижу всякий раз, когда сталкиваюсь с тем, что мы просто сложные приматы. - person Sedat Kapanoglu; 15.08.2011
comment
Для простых вещей используйте легкие. Проверьте этот крошечный и простой контейнер IoC с поддержкой IoC, DI и Auto-Wiring: mentacontainer.soliveirajr.com - person TraderJoeChicago; 08.09.2011
comment
Тот факт, что этот ответ является наиболее спорным ответом на SE, намекает на то, насколько модным (хорошим или плохим) стал Ioc / DI. Мне нравится ответ Джоэла, потому что он предлагает немного практической мудрости; ЯГНИ. Конечно, некоторые проекты требуют IoC, а другие - нет. Это хороший инструмент для ношения на поясе, но не используйте кувалду, чтобы вешать рамку для картины ... - person Didaxis; 14.09.2011
comment
IoC: скрыть сложность вместо ее решения (этот дерьмовый конструктор в другом ответе? Он все еще там); обменяйте ошибки времени компиляции на ошибки времени выполнения; делать возможными трудные для тестирования и трудно обнаруживаемые ошибки (ошибки при регистрации компонентов); отдавайте предпочтение классам богов (ядра). Все эти проблемы легко обнаружить в большинстве кодов IoC. Беспокоит то, что многие думают, что это хороший код. - person Sklivvz; 27.09.2013
comment
Конфигурация XML или внедрение зависимостей отлично работают даже в небольших проектах. Они улучшают ясность и структуру и (впервые) позволяют реализовать давнее требование объектно-ориентированного подхода - сделать код повторно используемым - путем отделения «связующего кода» от функционального кода. Они также позволяют программные продукты и настраиваемость для каждого клиента, чтобы легко менять стратегии / реализации / или алгоритмы ... в пределах одной и той же кодовой базы ... путем развертывания только одного измененного XML-файл. Например, другой ShippingCostCalculator. - person Thomas W; 24.11.2013
comment
И любого, кто не видит, насколько это чисто и мощно, следует на всю жизнь изгнать, чтобы он написал встроенный код для холодильников :) - person Thomas W; 24.11.2013
comment
+1 потому что им сложно понять, что многие простые программисты сочтут эти концепции запутанными. Эти люди обычно уделяют обычным программистам адское время. - person Dennis; 31.01.2014

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

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

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

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

По этому поводу есть отличное сообщение в блоге Марка Симанна: Когда использовать контейнер DI

person Community    schedule 19.09.2009
comment
Очень хороший ответ. Единственное, о чем я бы не согласился, это то, можно ли считать ручную инъекцию КОГДА-ЛИБО менее сложной или не рутинной. - person wekempf; 07.10.2009
comment
+1. Один из лучших ответов здесь. Спасибо также за ссылку на статью в блоге. - person stakx - no longer contributing; 27.10.2013
comment
+1 за уравновешенную точку зрения. Контейнеры IoC не всегда хороши и не всегда плохи. Если вы не видите в этом необходимости, не используйте его. Просто знайте, что инструмент есть, если вы действительно видите в нем необходимость. - person Phil; 28.03.2014

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

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

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, а не, IMHO, более запутанные файлы конфигурации, у вас могло бы быть что-то вроде этого:

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.
   }
}
person Community    schedule 16.05.2009
comment
Бен, вы говорите о местонахождении службы, а не о внедрении зависимостей - есть разница. Я всегда предпочитаю первое второму. stevenharman.net/blog/ архив / 2009 / 25.09 / - person stevenharman; 07.10.2009
comment
Вместо того, чтобы выполнять IoC.Resolve ‹T› в конструкторе по умолчанию, вы должны использовать возможность контейнера IOC для создания объекта за вас. Избавьтесь от этого пустого конструктора и позвольте контейнеру IOC построить объект за вас. var presenter = IoC.Resolve ‹CustomerPresenter› (); вуаля! все зависимости уже подключены. - person Ben Scheirman; 07.10.2009
comment
@ben, согласен! но не забывайте о прекрасном моменте, заключающемся в том, чтобы поместить это местоположение службы в какой-то уголок вашей инфраструктуры, ограничивая использование местоположения как можно меньшим количеством мест. - person stevenharman; 07.10.2009
comment
Обратной стороной централизации такой конфигурации является деконтекстуализация знаний. Джоэл указывает на эту проблему, говоря, что код становится, откровенно говоря, намного труднее читать. - person Scott Bellware; 07.10.2009
comment
@sbellware Я не согласен. Хотя некоторые знания становятся неконтекстуализированными, в любом случае это, скорее всего, шаблонный код, который просто отвлекает от реальной работы, которую пытается выполнить ваш класс и методы. - person Jesse C. Slicer; 07.10.2009
comment
@sbellware, какие знания? Интерфейс, рассматриваемый как первичная зависимость, служит контрактом, и его должно быть достаточно, чтобы передать его цель и поведение, не так ли? Я полагаю, вы можете иметь в виду знания, полученные в результате изучения выполнения контракта, и в каком случае вам нужно будет отслеживать соответствующую конфигурацию? Для этого я полагаюсь на компьютер (R # в VS, IntelliJ и т. Д.), Поскольку они отлично подходят для навигации по узлам и краям графа; Я оставляю стек своего мозга для контекста рабочего места, на котором я сейчас сосредоточен. - person stevenharman; 07.10.2009
comment
Стив, я знаю текст .NET и много лет ходил по этому пути. Я также хорошо знаком с другими режимами и формами, и я интуитивно понимаю, что есть реальные компромиссы. Я знаю, как и когда идти на эти компромиссы, но разнообразие моей рабочей жизни, по крайней мере, позволяет мне ощутимо понять точку зрения Джоэла. Вместо того, чтобы читать мне лекции об инструментах и ​​приемах, которые я использую дольше, чем большинство монокультурников .NET, расскажите мне то, чего я не знаю. Я оставляю стек своего мозга для разнообразного, критического мышления, а не для застоя и ортодоксальности alt.net. - person Scott Bellware; 07.10.2009
comment
Джесси, шаблон - это перспектива. Я не высказываю суждений об этой перспективе, но хочу сказать, что это просто перспектива. - person Scott Bellware; 07.10.2009
comment
Скотт, я понимаю точку зрения Джоэла; когда конфигурация происходит, то есть потеря контекстного знания, ну ... вне контекста ее использования. И я не пытался читать лекции об инструментах или приемах, чтобы обойти этот компромисс. Скорее, я наблюдал, что в контексте определенных архитектурных ограничений (в данном случае: .NET, JAVA или любой другой язык, требующий контейнера), почему бы не полагаться на инструменты для выполнения такой работы, когда вы можете ? Я должен был быть более ясным в контексте, в котором я делал это заявление. - person stevenharman; 08.10.2009
comment
Согласитесь с централизованным подходом. Распространять конфигурацию - это плохо, но это мое личное предпочтение. Вот почему я предпочитаю программную конфигурацию XML и аннотациям. Взгляните на подход к настройке, сделанный здесь: mentacontainer.soliveirajr.com - person TraderJoeChicago; 08.09.2011
comment
Шаблон Service Locator (описанный здесь) на самом деле считается анти-шаблоном некоторыми, например то, чего не следует придерживаться. Должен сказать, что согласен с ними. Service Locator плохой, правильная инъекция зависимостей намного лучше. - person Per Lundberg; 17.10.2013

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

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.
}
person Community    schedule 16.05.2009
comment
Но класс IoC вызывается с использованием антишаблона локатора сервисов. Should_container передается с использованием конструктора DI вместо вызова статического T Resolve ‹T› ()? - person Michael Freidgeim; 24.03.2013
comment
@bendewey Ваш пример подразумевает, что он автоматически передает аргументы конструкторам для new CustomerService и new CustomerRepository. Вот как это работает? Что делать, если у вас есть и другие дополнительные параметры? - person Brain2000; 25.04.2013

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

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

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

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

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

person Community    schedule 16.05.2009
comment
Мне нравится ваше наблюдение о неизбежном наличии сложности. Разница между подключением зависимостей на основе контейнера и вручную заключается в том, что с помощью контейнера вы можете сосредоточиться на каждом компоненте индивидуально и, таким образом, управлять возрастающей сложностью довольно линейным образом. Системы с ручным подключением зависимостей сложнее развить, поскольку процесс настройки одного компонента трудно отделить от настройки всего остального. - person Nicholas Blumhardt; 16.08.2009
comment
Мне нравится AspectJ. Это не Java, но и не XML. Это своего рода IS Java в том смысле, что он ощущается и выглядит как Java, будучи его расширением. Я бы предпочел не включать свои аспекты в свои POJO и в свою бизнес-логику. Я почти тоже хотел бы, чтобы мои IoC не выходили. ИМХО, слишком много XML для подключения инструментов. Если мне нужны файлы конфигурации, пусть это будут сценарии BeanShell. / Java, примените свои аналоги .Net здесь - ›. - person Chris K; 14.05.2010
comment
Я, конечно, понимаю ваш ответ, но я думаю, что большая часть проблемы заключается в том, что многие фреймворки IoC (и, на самом деле, множество других фреймворков для других вещей) описаны и задокументированы для других, уже хорошо знакомых с необходимые понятия и терминология. Я узнал о многом из этого, только что унаследовав код другого программиста. Я изо всех сил пытаюсь понять, почему код использует IoC, когда «графы объектов» довольно малы и нет реального тестового покрытия кода. Как программист SQL вы, вероятно, лучше оцените использование IoC с ORM. - person Kenny Evitt; 18.07.2013
comment
@KennyEvitt, хороший момент, казалось бы, преждевременно использовать фреймворк IoC, если у вас есть простое приложение и вы даже не позаботились о хорошем тестовом покрытии. - person Bill Karwin; 18.07.2013

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

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

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

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

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

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

Плюсы при выборе стороннего контейнера IoC

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

Минусы

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

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

person Community    schedule 19.09.2009
comment
Я согласен с вами, Сэм - DI - это тип IoC, поэтому, если исходный плакат выполняет DI, они уже делают IoC, поэтому реальный вопрос заключается в том, зачем катить собственный. - person Jamie Love; 08.10.2009
comment
Я не согласен. IOC - это способ сделать DI. Контейнеры IOC выполняют DI, беря под контроль создание экземпляров типа с помощью динамического отражения среды выполнения для удовлетворения и внедрения зависимостей. OP предполагает, что он выполняет статический DI, и размышляет, почему ему нужно жертвовать преимуществами проверки времени компиляции на преимущества, часто связанные с динамическим отражением времени выполнения IOC. - person Maxm007; 14.01.2013

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

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

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

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

  • Если вы хотите использовать АОП для решения общих задач, IoC предоставляет перехватчики для перехвата вызовов методов. Реже это делается специально для проектов, но IoC упрощает эту задачу.

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

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

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

person Community    schedule 16.05.2009

Я выздоравливающий наркоман МОК. В наши дни мне трудно оправдать использование 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.

person Community    schedule 10.01.2013
comment
Мне это кажется аргументом не против IoC, а как аргумент против настраиваемых фреймворков IoC. Разве ваши фабрики здесь не сводятся к простым жестко запрограммированным IoC? - person Mr.Mindor; 03.08.2013
comment
Я думаю, когда плакат упоминал IoC, имелся в виду контейнерный фреймворк IoC. Спасибо за первоначальную запись, это помогает убедить меня отказаться от фреймворка. Итак, если он настраивается в тестах и ​​в производственном коде, в чем преимущество настраиваемого фреймворка? - person huggie; 05.12.2013
comment
Насколько я понимаю терминологию, Inversion Of Control означает поиск зависимостей во время выполнения. Итак, да, вы могли бы сказать, что фабрика в основном представляет собой жестко запрограммированный или статический контейнер, но это не контейнер IOC. Типы разрешаются во время компиляции. Это аргумент против использования настраиваемых фреймворков, которые используют поиск по словарю для определения типов во время выполнения. - person Maxm007; 12.03.2014

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

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

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

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

person Community    schedule 08.10.2009
comment
Это огромный плюс. Не могу поверить, что никто не упомянул об этом раньше. Без необходимости передачи или сохранения временных объектов код становится намного чище. - person Finglas; 07.03.2010
comment
они волшебным образом появляются, когда они мне нужны! - Я могу рассказать вам небольшой секрет - просто используйте глобальные объекты, и они волшебным образом появляются, когда они вам нужны, без какого-либо раздувания iocc! - person qble; 11.07.2013
comment
Глобальные объекты @qble отлично работают ... если вы хотите, чтобы ваша кодовая база была тесно связанным, непроверяемым кошмаром, который со временем становится все труднее и труднее изменять. Удачи с этим. - person Jeffrey Cameron; 11.07.2013
comment
Контейнер IoC @JeffreyCameron - глобальный объект. Он не удаляет ваши глобальные зависимости. - person qble; 11.07.2013
comment
Верно, однако контейнер IoC прозрачен для остальной части приложения. Вы вызываете его один раз при запуске, чтобы получить экземпляр, а затем это последнее, что вы его видите. С глобальными объектами ваш код завален жесткими зависимостями - person Jeffrey Cameron; 11.07.2013
comment
@qble, если ваш контейнер IoC является буквально глобальным объектом и ваш проект завален ссылками на него, вы используете его неправильно. Как говорит Джеффри, если у вас есть какие-либо ссылки помимо конфигурации и использования ее для запроса экземпляра при запуске, вы делаете это неправильно. - person Mr.Mindor; 03.08.2013
comment
@JeffreyCameron, вы вызываете его один раз при запуске, чтобы получить экземпляр, а затем это последнее, что вы его видите. - как бы вы создавали экземпляры объектов без ioc-контейнера? - person qble; 04.08.2013
comment
@qble использует фабрики для создания временных экземпляров на лету. Фабрики - это одноэлементные сервисы. Если временным экземплярам требуется что-то из контейнера IOC, подключите их к фабрике и заставьте фабрику передать зависимость в временный экземпляр. - person Jeffrey Cameron; 05.08.2013
comment
Конфигурация XML и IoC действительно проще, чище и лучше. Если у вас есть реальный программный продукт с более чем одним клиентом, вы можете поменять стратегии / алгоритмы внутри одной и той же кодовой базы, развернув только один измененный файл XML. Доступ к службам или настройкам значительно упрощен, и впервые в истории объектно-ориентированного проектирования вы можете фактически повторно использовать свой код в других проектах, потому что он больше не склеен жестко зашитым клеем. - person Thomas W; 24.11.2013
comment
@Thomas Я бы сказал, что ваша реализация - антипаттерн. Ваша конфигурация должна быть выбрана с помощью свойств, которые задаются либо пользователем при запуске приложения, либо лицом, развертывающим приложение в среде. В любом случае конфигурация должна оставаться той же, но отличается то, как она настраивается. В этом случае ваша конфигурация статична и не имеет значения, в XML она или в коде. Однако код можно отредактировать, а XML - нет. Это объясняет мои предпочтения при настройке в коде. - person Jeffrey Cameron; 25.11.2013
comment
Конфигурация XML определенно была чище, элегантнее и позволяла многократно использовать чрезвычайно эффективный способ. Это абсолютно не антипаттерн. - person Thomas W; 26.11.2013
comment
@ Томас Возможно, я не совсем понял. Я не утверждал, что конфигурация XML - это антипаттерн. Скорее, необходимость настроить ваш файл XML для развертывания в новой среде была анти-шаблоном. Мы также используем конфигурацию XML, но то, что может измениться в зависимости от среды, выбирается через файлы свойств. Дело в том, что если вы используете файлы свойств, то не имеет значения, используете ли вы XML или конфигурацию кода. Если это не имеет значения, почему бы не пойти на простой рефакторинг и типобезопасность конфигурации кода? - person Jeffrey Cameron; 26.11.2013
comment
Я использую для этого свойства! Свойства для параметров сервера и развертывания, XML для структуры приложения, а также для очистки кодовой базы и включения возможности повторного использования, устраняя необходимость в связке, зависимостях инициализации и вручную реализованной конфигурации в кодовой базе. - person Thomas W; 26.11.2013
comment
Если вы передаете ссылки по деревьям объектов, вы не выполняете внедрение зависимостей. Вы можете избежать прохождения этих иголок, не обращаясь к контейнеру IOC, если обычные объекты не создают другие объекты. Только фабрики могут создавать объекты, которые вы передаете через конструктор. В корне своей программы вы создаете фабрики и службы и строите свою иерархию объектов. Никаких лишних прохождений по этому пути. - person Maxm007; 02.04.2014

Фреймворки IoC отлично подходят, если вы хотите ...

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

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

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

Проблема с 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-часть, и это должно быть предупреждающим знаком о том, что что-то не так с вашим дизайном, если вы его получили.

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

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

data Foo = Foo { apa :: Bar }

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

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

и ввести (но я бы не назвал это инъекцией) Bar.

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

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

person Community    schedule 13.10.2009
comment
выбросьте безопасность типов - за исключением того, что ваш пример по-прежнему безопасен по типу, вот что такое интерфейс. Вы не передаете типы объектов, а тип интерфейса. И безопасность типов в любом случае не отменяет исключений с нулевыми ссылками, вы можете с удовольствием передавать пустые ссылки как типобезопасные параметры - это вообще не проблема безопасности типов. - person blowdart; 13.10.2009
comment
Вы отбрасываете безопасность типов, так как не знаете, подключен ли тип к IoC-контейнеру (тип IoC ‹IBar› не IBar, это фактически IO IBar) .. И да, в Haskell -example Я не могу получить нулевую ссылку. - person finnsson; 13.10.2009
comment
Безопасность типов на самом деле не связана с подключением объекта, по крайней мере, не в Java / C #, а просто в том, что объект имеет правильный тип. И ConcreteClass myClass = null по-прежнему имеет правильный тип. Если вы хотите принудительно применить not null, тогда вступают в игру контракты кода. - person blowdart; 13.10.2009
comment
Конечно, нулевые указатели могут существовать в C # / java без IoC, но вы бы не написали foo = null; foo.ToString(), но это то, что вы можете получить с помощью IoC-frameworks. ToString требует объект, который может отличаться от типа объекта. Тот факт, что c # / java / javascript не делает различия во времени компиляции между Object и Maybe Object, не означает, что нет никакой разницы (т.е. есть разница). Таким образом, вы получите меньшую безопасность типов при использовании IoC-фреймворков. Помимо этого, я думаю, что меньшая безопасность типов - это второстепенная проблема по сравнению с глобальными переменными, которые вводит IoC. - person finnsson; 13.10.2009
comment
Я согласен с вашим 1-м пунктом до некоторой степени, я хотел бы, чтобы какое-то объяснение 2-го и 3-го никогда не было для меня проблемой. В вашем примере C # контейнер IoC используется в качестве локатора службы, что является распространенной ошибкой. И сравнение C # и Haskell = яблоки и апельсины. - person Mauricio Scheffer; 15.10.2009
comment
очевидно, вы не понимаете, что такое DI и что такое шаблон локатора служб .. - person Carl Hörberg; 30.07.2010
comment
Вы не выбрасываете типобезопасность. Некоторые (если не большинство) контейнеров DI позволяют проверить полный граф объекта после процесса регистрации. При этом вы можете предотвратить запуск приложения из-за неправильной конфигурации (быстрого сбоя), и в моих приложениях всегда есть несколько модульных тестов, которые вызывают производственную конфигурацию, чтобы я мог найти эти ошибки во время тестирования. Я бы посоветовал всем, кто использует контейнер IoC, написать несколько модульных тестов, чтобы убедиться, что все объекты верхнего уровня могут быть разрешены. - person Steven; 06.11.2011
comment
Вы все в насильственном согласии. Когда автор говорит об отказе от безопасности типов, он имеет в виду, что проблемы конфигурации контейнера IoC не могут быть обнаружены компилятором. Вместо этого ошибки могут быть обнаружены только во время выполнения, фреймворки IoC заставляют вас выполнять код, если вы хотите быть уверенным, что все подключено правильно. проверка [ing] полного графа объекта после процесса регистрации может быть полезна, но это не безопасность типов. - person liammclennan; 16.03.2014

Я обнаружил, что правильная реализация внедрения зависимостей заставляет программистов использовать множество других методов программирования, которые помогают улучшить тестируемость, гибкость, ремонтопригодность и масштабируемость кода: такие практики, как принцип единой ответственности, разделение проблем и кодирование. против 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 вручную в каждом контроллере, действительно возрастет по мере роста вашего приложения. Если у вас есть приложение только с одним корнем контекста, которое никогда не пытается создать экземпляр службы путем отражения, то это не такая уж большая проблема. Тем не менее, любое приложение, использующее внедрение зависимостей, станет чрезвычайно дорогостоящим в управлении, когда оно достигнет определенного размера, если вы не используете какую-либо структуру для управления графом зависимостей.

person Community    schedule 17.06.2010

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

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

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

person Community    schedule 07.10.2009

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

person Community    schedule 16.05.2009

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

Но если вы строго следуете шаблону DI, вы обнаружите, что его наличие удалит тонну избыточного и скучного кода.

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

person Community    schedule 17.12.2009

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

person Community    schedule 07.10.2009
comment
но я инженер, работающий над интернет-технологиями в 21 веке, так что я к этому привык - ›+1 - person user96403; 05.07.2012

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

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

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

person Community    schedule 07.10.2009
comment
почему мы продолжаем умиротворять наименьший общий знаменатель, а не работать над их улучшением? - person stevenharman; 07.10.2009
comment
Я ничего не сказал об умиротворении. Я просто сказал, что расширенные сценарии могут сделать вещи более запутанными для новых разработчиков - это факт. Я не говорил, так что не делай этого. Но даже тогда (время для адвоката дьявола) часто есть другие способы сделать то же самое, что сделает кодовую базу более явной и доступной. Скрытие сложности в пользовательской конфигурации вашего инструмента инфраструктуры только потому, что вы можете это сделать, - не правильная причина, и это никого не привлекает. - person Aaron Lerch; 07.10.2009

То же о Unity. Если стать слишком большим, можно услышать скрип стропил.

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

person Community    schedule 08.10.2009

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

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

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

person Community    schedule 16.05.2009
comment
Новая структура MEF позволяет именно это для .NET, и я должен сказать, что код чище и легче для понимания, что значительно упрощает понимание концепции DI. - person terjetyl; 07.10.2009
comment
@TT: MEF не контейнер для внедрения зависимостей и не имеет ничего общего с АОП. - person Mauricio Scheffer; 15.10.2009

Итак, прошло уже почти 3 года, а?

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

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

`@Configuration общедоступный класс AppConfig {

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

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

} `И для этого нам нужен фреймворк, почему именно?

person Community    schedule 21.07.2013

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

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

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

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

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

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

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

person Community    schedule 08.03.2013
comment
Даже для небольших проектов размещение конфигурации в XML делает его более чистым и модульным - и впервые делает код пригодным для повторного использования (поскольку он больше не загрязнен клеем). Для правильных программных продуктов вы можете настроить или поменять местами, например, ShippingCostCalculator или ProductUIPresentation, или любую другую стратегию / реализацию, в той же самой кодовой базе, развернув только один измененный файл XML. - person Thomas W; 24.11.2013
comment
Если это будет реализовано волей-неволей, в качестве общей практики, я думаю, вы добавите больше сложности, а не меньше. Когда вам нужно что-то поменять местами во время выполнения, они великолепны, но зачем добавлять обфускацию? Зачем оставлять накладные расходы на дополнительные интерфейсы для вещей, которые никогда не будут отключены? Я не говорю, что не используйте IoC для тестирования. В любом случае используйте инъекцию зависимостей свойств или даже конструкторов. Вам нужен интерфейс? Почему бы не создать подклассы для ваших тестовых объектов? Разве это не было бы чище? - person Fred; 25.11.2013
comment
Вам вообще не нужны интерфейсы для настройки XML / IoC. Я обнаружил большие улучшения в ясности в небольшом проекте всего с ~ 8 страницами и 5 или 6 услугами. Здесь меньше запутывания, поскольку сервисам и контроллерам больше не нужен связующий код. - person Thomas W; 25.11.2013

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

person Community    schedule 12.08.2013

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

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

person Community    schedule 10.09.2013

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

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

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

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

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

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

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

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

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

person Community    schedule 11.02.2014

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

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

person Community    schedule 07.10.2009

КОНТЕЙНЕР МОК РЕШАЕТ ПРОБЛЕМУ, КОТОРОЙ МОЖЕТ НЕ БЫТЬ, НО ЭТО ПРИЯТНАЯ ПРОБЛЕМА ИМЕТЬ

http://kozmic.net/2012/10/23/ioc-container-solves-a-problem-you-might-not-have-but-its-a-nice-problem-to-have/

person Community    schedule 25.11.2013

вам не нужен фреймворк для внедрения зависимостей. Вы также можете сделать это с помощью основных концепций Java. http://en.wikipedia.org/wiki/Dependency_injection#Code_illustration_using_Java

person Community    schedule 07.02.2014

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

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

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

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

person Community    schedule 27.03.2014

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

person Community    schedule 07.10.2009
comment
можешь привести пример? Чем DI отличается в ASP.NET от приложений любого другого типа? - person tofi9; 19.02.2010