Pull to refresh

Comments 46

Завтра продолжим эту тему, хочется услышать об опыте коллег, а так же сравнить существующие контейниры
Я делал сравнение (на английском), будет интересно почитать что изменилось.
Да, кстате, спасибо за обзор в вашем блоге.
Итак, какие у нас выводы? Unity, судя по всему, на порядок проще Spring и намного лучше подходит для обучения, имхо. Автопроксиинг всех объектов контейнера — зачем? Когда это действительно нужно? =)
Не плохо. я этого не знал. Но не хватает примера по-серьёзнее (из практики например).
Получается, что все объекты, определённые как имеющие интерфейс IService, будут инициализироваться экземпляром MyService? Или это пример так подобран?

Другими словами, если мне необходимо иметь 2 объекта с интерфейсом IService в одном MyWindow, то фреймворк позволит это сделать?
Конечно! Система предельно гибкая. Можно написать например:
public class MyWindow
{
 public IService firstService, secondService;
 public MyWindow(IService first, IService second)
 {
  firstService = first;
  secondService = second;
 }
}
Только не забудьте, что by default, контейнер выдает синглтоны. Чтобы получить разные копии сервисов, нужно слегка изменить регистрацию:
var uc = new UnityContainer();
uc.RegisterType<IService, MyService>(new ExternallyControlledLifetimeManager());
Application.Run(uc.Resolve<MyWindow>());
Я так понимаю спрашивалась ситуация, когда будет:
public class MyFirstServiceImpl : IService{}
public class MySecondServiceImpl : IService{}
Тогда есть сразу несколько вариантов ответа :) Например использовать InjectorProperty. Или добавлять marker interface для обоих сервисов. Или декларировать их как конкретные типы. Или задать им имена и резолвить вручную, по имени. (но это уже не DI)
Ха! Ошибся. Не знаю что в голову ударило… конечно дефолтное поведение не синглтон :) Сорри!
Вопрос в том различаются эти обекты, или нет.
По логике, если они имплементируют один и тот же интерфейс, то и использование у них будет однородное.

В таком случае параметр можно заменить на IService[] services и дальше работать со всеми имплементациями сразу.
Это тоже, кстати, вариант.
UFO landed and left these words here
Другие контейнеры тоже хороши. Правда, насколько я помню, Spring поддерживает только конфигурацию в XML, что лично мне не нравится. Обычно происходит так: с чем разработчик начинает работаеть, то и использует. Разница во фреймворках редко переманивает его с одного на другого.

Примеров актуального использования контейнеров в сети — миллион. Один из примеров — когда при неправильно работающем приложении нужно заменить обычную реализацию на динамический прокси с детальным логгированием. Без перекомпиляции. На живой системе. Тут-то внешняя конфигурация и спасает — меняем XML и все. А вообще примеров много, если долго пользовать, то потом не сможешь без этого жить.

Насчет Unit-тестирования — допустим объект А зависит от В, а от — от С. С создается в В без моего ведома. А теперь вопрос — как я могу подменить тот объект, который создается без моего участия вообще? Правильно, я не могу — если только не начну вообще все цепочки создавать вручную, что просто нереально. С контейнером же, я могу подменить реализацию объекта, независимо от того, на какой он «глубине» находится.

Тут я имел ввиду что если, например, для использования какого-то сервиса его нужно настраивать (к пр. передавать гору данных в конструктор), то легче это действие централизовать чтобы потом можно было эту конфигурацию менять централизованно. В тех же unit-тестах, например.
Незнаю как в версии для .NET, но в версии для Java Spring уже давно поддерживает конфигурацию аннотациями.
Можно конфигурировать содержимое IoC контейнера Spring.NET и в коде и даже в стиле Fluent.
Unity предоставляет возможность конфигурирования без XML файлов. Вся конфигурация выполняется средствами языка, что гораздо удобнее и надежнее. Тоже самое можно сказать про фреймворки Autofac и Ninject — последний мой любимый, им я и пользуюсь. Если кому то это интересно, у меня есть PowerPoint презентация про Ninject — могу выложить.

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

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

Цель DI — избежать самокофигурирующихся объектов, т.к. это снижает возможность их повторного использования и тестирования.
На презентацию бы глянул :)
Я подумал… Я ее переделаю, расширю и выложу как несколько статей. В том числе и про использование Ninject совмесно с ASP.NET MVC.
Кстати да, как раз две темы которые, как мне кажется, стоит осветить (хотя в других блогах они есть) — это поддержка asp.net mvc и wpf (хотя постойте, у autofac с mef тоже интеграция есть что ли?). Другое дело что поскольку эта инфа уже есть где-то еще, не уверен что ее стоит пеперисывать. Может и стоит, ради того чтобы она была понятней.
Есть, и с MEF и с MVC и просто c ASP.NET
Спринг плох XML-настройкой, в большом приложении это просто лишняя работа как при разработке так и при поддержке.

Если в бизнес приложении никогда нет необходимости в автоматическом IService[], то это не слишком удачная архитектура.
Фабрики надо писать и поддерживать, хороший контейнер — не надо (XML ни разу не использовал, зачем).

В юнит тестировании очень помогает automocking container, но это не столь важно. Важнее то, что когда классы спроектированны так, чтобы все вспомогательные объекты можно было переопределить через свойства или конструктор, то чтобы создать их в самом приложении можно:
a) либо написать много кода, который ссылается на все библиотеки приложения и требует поддержки
б) использовать IoC

Я обычно выбираю пункт б).
Я не согласен с Вами насчет юнит тестирования.

Одна из идей IOC в том, чтобы собрать независимые модули системы вместе. А идея юнит тестирования чтобы эти независимые модули протестировать. Так что IOC и юнит тестирование тесно связаны и всегда используются вместе.
у нас в огромном проекте используется spring именно для IoC.
позволяет переконфигурировать приложение без перекомпиляции. Модули (jar'ки) добавляются, удалятся, заменяются, переопределяя друг друга — в итоге получаем нужную конфигурацию для конкретного деплоймента.
>Ни одного реального, а главное уместного примера применения IoC контейнеров в бизнес приложениях пока не встречал…

Давайте я дам конкретный пример.
У меня есть модуль–блог. Данные храню на своем сервере. Пришел заказчик, сказал, что у него уже есть блог на Google Blogger'e. Поскольку у меня был легкий сервис, отделенный от всей логики, который только и делал, что писал и читал в/из базы, я заменил его другим, который стал писать и читать в/из сервисов Google Blogger.

Применив Unity, я заменил только тонкий сервис, не трогав ничего остального и не переписывая тесты главной логики.

Если завтра придет другой чувак и попросит использовать другой движок – сделать это будет легко, и самое главное – у меня не будет болеть голова, что я что–то сломаю. Тесты проходят на главную логику, отдельные на сервис – значит все в порядке.
>Вопрос такой, в какой системе IoC контейнер может быть полезен при разработке бизнес приложений и на бою?

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

>Чем IoC лучше?
Да ничем он не лучше. Это просто паттерн автоматического определения зависимостей. Он есть в контейнере Unity. Контейнер Юнити описывается автором только потому, что это типа «модное и современное» решение, хотя, судя по ответам на технические вопросы, автор только-только что-то прочитал. IoC можно вообще убрать, написав свой контейнер или взяв простой существующий. System.ComponentModel.Design.ServiceContainer, например (хотя, если вы джавист, то это вам ничего не скажет).

Фишка удобства тестирования не выходит из концепции Unity, а выходит из концепции построения классов, которые удовлетворяют шаблону определения зависимостей. Ты должен или проставить зависимость в конструкторе или в свойстве класса, причем, желательно определив интерфейс. Значит, очень легко настроить mock зависимостей (мок интерфейса очень легко сделать) и протестировать фукнционал класса. Unity контейнер здесь не причем. Он всего лишь вставляет зависимости.

Вы не могли бы к этому элементарному примеру ещё сделать такой же пример по юнит тестам, про которые упомянули.
Обязательно — возможно в следующем посте.
А вот есть прикольная задачка уже не для начинающих — связать ASP.NET MVC с Unity. Требований в целом три:

— обеспечить связывание инфраструктуры контроллеров MVC с инъектором
— модульность
— уникальность контейнера в разрезе сессии

Я бы расписал все, но блин, не успеваю вообще ничего, кроме работы. А вам в рамках обучающих методик будет полезно, имхо.
Да, для WPF тоже есть свои особенности. Было бы неплохо все это покрыть, но я не знаю, нужна ли хабру серия постов про Unity/DI/IoC.
Мне это было бы очень интересно. Думаю я не один такой.
Категорически нужна.
Хорошие скринкасты с введением в IoC контейнеры Castle Windsor (наверное, самый сейчас популярный), Ninject и StructureMap. На английском.

dimecasts.net/Casts/ByTag/IoC
Около года назад тоже озадачились выбоорм IoC фреймворка. Выбрали Autofac. Кроме различных вкусностей, понравилась его легковесность и простота конфигурации. Всё-таки Unity немного громоздок, посмотрите например на код его материализатора объектов.

P.S. IoC используем для разработки линейки продуктов.
Хм. Чем вам не угодил IServiceProvider и IServiceContainer из 2.0? Использование новых версий C# это раз, использование стороннего фреймфорка — два. Когда можно сделать (а в этом случае уже сделано) проще, то зачем платить больше?
* сделано — имелась в виду реализация ServiceContainer из System.ComponentModel.Design
Если я правильно понимаю, ServiceContainer требует чтобы все объекты были созданы заранее, или явно создавились через callback.
Тогда непонятно в чём бонус.

А разве можно написать хоть немного сложное приложение без использования сторонних фреймворков?
Service Provider — это совсем не Dependency Injection.
Кстати говоря, есть отличный майкрософтовский фреймворк, использующий паттерны DI и IoC. Называется Smart Client Software Factory (SCSF). Мы его юзаем в нашем проекте. Все довольны. А для Java, как уже было сказано выше существует Spring Framework.
Предлагаю заглянуть в блог одного моего товарища: gandjustas.blogspot.com . Там есть толковые посты по теме, найти их можно по тегам «UNITY», «IOC-КОНТЕЙНЕР».
У меня дурацкий вопрос.
Если абстрагироваться от всяческих фреймворков и .NET… Правильно же, что IoC это такой хитрый контейнер, который может отдать объект по классу. А если он ещё и отслеживает зависимости и удовлетворяет их, то тут ещё и DI.
Так вот вопрос: если всё это так, то чем IoC-контейнер отличается от фабрики?
Это по сути и есть фабрика. В spring прямо так и называется BeanFactory. Т.е. BeanFactory и является IOC контейнером.

BeanFactory factory = new XmlBeanFactory(«beans.xml»);
Здесь нужно уточнить. Контейнер отличается от фабрики прежде всего, тем, что сохраняет ссылки на создаваемые им объекты и управляет их жизненным циклом. Фабрика же занимается только созданием объектов. пруф1, пруф2

В spring IoC контейнер создается как объект ApplicationContext.
The interface org.springframework.context.ApplicationContext represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the aforementioned beans.
При этом ApplicationContext наследует также от BeanFactory
public interface BeanFactory
The root interface for accessing a Spring bean container. This is the basic client view of a bean container; further interfaces such as ListableBeanFactory and ConfigurableBeanFactory are available for specific purposes.
Т.е. IoC контейнер в Spring является также и фабрикой, но имеет более широкий функционал, чем создание объектов. В официальной документации для создания контейнера рекомендуется использовать ApplicationContext. пруф3
Паттерн DI — это одна из реализаций принципа IoC
Only those users with full accounts are able to leave comments. Log in, please.