Dependency injection

3,537 views

Published on

Видеозапись:
http://getdev.net/Event/dependency-injection

Рассказ о внедрении зависимостей (Dependency Injection), зачем оно нужно, откуда оно пошло и развивалось. Виды Dependency Injection, разница между ними и рекомендации к применению. Расказ про декораторы (decorators). Рассказ про абстрактные фабрики. Рассказ про управление временем жизни. Рассказ про IoC -контейнеры вообще и Castle Windsor в частности.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,537
On SlideShare
0
From Embeds
0
Number of Embeds
653
Actions
Shares
0
Downloads
29
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Dependency injection

  1. 1. Андрей КулешовДеловые решения
  2. 2. Про что мы говорим? В первую очередь – про подход к взаимодействую между классами и объектами в мире объектно- ориентированного программирования Во вторую очередь – про существующие шаблоны реализации этого подхода И только в третью очередь – про сторонние компоненты - IoC-контейнеры
  3. 3. Спагетти-код и лазанья-код Спагетти-код – это код, представляющий собой одну большую хаотичную мешанину классов, отвечающих за все функции вашего приложения Лазанья-код - это код, представляющий собой несколько отдельных маленьких хаотичных мешанин классов – слоёв, взаимодействующих друг с другом по строго определенным контрактом, не зависящим от реализации. Классическая модель – всем известная уровень данных, уровень бизнес-логики, уровень пользовательского интерфейса. Но их может быть больше.
  4. 4. Формирование слоёв Слой – группа классов, имеющих схожее назначение Взаимодействие между слоями идёт через «швы» Взаимодействие через швы должны идти только через контракты (интерфейсы или абстрактные классы), а не конкретные реализации И этим вы сможете добиться, что маленький локальный хаос внутри конкретного слоя останется таковым, а не разрастется на всё приложение
  5. 5. Что такое «зависимость» («dependency») Что-то сильно внешнее по отношению к нашему классу, медленное, тяжелое в настройке, а также просто ещё не готовое.. В первую очередь это: - файловая система; - база данных - сеть; - сервис, который коллега послезавтра обязательно допишет; - система старта ракетных двигателей. Ваш класс должен зависеть от абстракций, а не от конкретных реализаций
  6. 6. Классическая работа сзависимостями: Когда вы напрямую создаёте экземпляр объекта в вашем классе - вы контролируете его IDbConnection connection = new SqlServerConnection(“source=localhost”); Контролируете, когда он создается, какие параметры принимает, когда он больше не нужен и его надо удалять Контролируете, что создается именно этот тип объекта, а не схожий по функиональности То есть всерьез декларируете, что класс, который считает сумму заказов в вашей корзине покупок, должен знать о балансированной ферме Sql Server, и том, какой таймаут допустим при работе с ней
  7. 7. ДемоКлассический контроль
  8. 8. Inversion of ControlИнвертированный контроль: При использование IoC – ваш класс больше не имеет контроля над зависимостями public class Basket{ public Basket(IDbConnection connection){ //save connection... } } Об этом заботится кто-то снаружи этого класса Кто-то, кто знает больше и лучше. Кто на этом специализируется А ваш класс перестаёт зависеть от конкретной реализации
  9. 9. Что злобные врагирассказывают вам об DI DI – это «локатор сервисов» нагло врут DI нужен только для тестирования нагло врут DI нужен только для позднего связывания нагло врут Для архитектуры в стиле DI нужен IoC контейнер нагло врут
  10. 10. Как всё начиналось Одним из первых паттернов, способствующих уменьшению связности между классами, был локатор сервисом (Service Locator) До сих пор он у многих ассоциируется с понятием Dependency Injection Однако сейчас он считается скорее анти- паттерном, не рекомендуемым к применению Основная проблема – неявные требования при работе с классами, использующими локаторы сервисов
  11. 11. ДемоЛокатор сервисов
  12. 12. Как внедрять зависимости?Основное требование – объект всегда должен быть в рабочемсостоянии.Если зависимость неявная – значит, она должна бытьнеобязательной.Ни при каких обстоятельствах не должен происходитьNullReferenceExceptionЧетыре стандартных подхода: Вставка через конструктор (constructor injection) Вставка через свойства (property injection) Вставка через параметры методов (methods injection) Использование общедоступного внешнего контекста (ambient context)
  13. 13. Constructor Injection Используется для всех зависимостей, без которых классу не обойтисьpublic class GreetingsManager{ private readonly IWriter _writer; public GreetingsManager(IWriter writer) { if(writer == null) throw new ArgumentNullException("writer", "Writer was not provided"); _writer = writer; } ... ...}
  14. 14. ДемоConstructor Injection
  15. 15. Property Injection Используется для всех public class GreetingsManager опциональных { зависимостей private IWriter _writer = null; Или для зависимостей, у public IWriter Writer которых есть локальная { реализация по умолчанию get { То есть когда в 90% случаев if(_writer == null) подойдет стандартная, но { иногда нужно иметь _writer = new ConsoleWriter(); возможность заменить… } Возможно, иногда также return _writer; подойдет NullObject – } паттерн, то есть объект- set заглушка, не выполняющая { действий if(_writer != null) throw new(пример не совсем чистый – в InvalidOperationException(примерах кода GreetingsManager и "You cant change writerConsoleWriter находятся в разных implementation after usage");сборках. Локальная реализациядолжна принадлежать той же сборке) _writer = value; } }
  16. 16. ДемоProperty Injection
  17. 17. Method Injection Имеет смысл использовать, если зависимость меняется от метода к методу Также удобно использовать при написании собственного фреймворка, когда мы хотим передать получателю (например, стороннему плагину) некий контекст, хранящий информацию о вызывающей стороне public string RunPlugin(SomeValue value, ISomeContext context) { if (context == null) { throw new ArgumentNullException("context"); } return context.Name; }
  18. 18. ДемоMethod Injection
  19. 19. Ambient Context Некий контекст, который с большей долей вероятности может понадобиться (а может и не понадобится) в большинстве разрабатываемых классов Чтобы не передавать зависимость в каждый из разрабатываемых классов – применяем общедоступный Ambient Context Пример использования – текущее время (но с возможностью подмены значения)
  20. 20. ДемоAmbient Context
  21. 21. Абстрактные фабрики Удобно использовать для инстанциирования короткоживущих объектов Удобно использовать для инстанциирования объектов, когда тип создаваемых объектов зависит от параметров, известных только во время выполнения Удобно использовать, когда создание зависимости стоит дорого, а нужно не при каждом использовании класса
  22. 22. Декораторы Цепочка из декоратор позволяет нам в полной мере реализовать Open/Closed принцип – создавать классы, закрытые для модификаций, но доступные для расширения Только для расширения мы будем применять не наследование от этого же класса, а наследование от абстракции По сути, декоратор – это умный прокси.
  23. 23. Так кто же создает всюиерархию? В идеале – одно место в приложении, где формируется весь граф зависимостей (паттерн Composition Root) В идеале – одно на всё приложение место, где мы запрашиваем объект – вершину пирамиды зависимостей Современные фреймворки создаются с учетом этого требования Так, в жизненном цикле запроса к ASP.NET MVC таким местом является ControllerFactory
  24. 24. ДемоComposition Root своими руками
  25. 25. Управление временем жизниLifestyle ОписаниеSingletone Единственный экземпляр, предоставляемый всем потребителямTransient Новый экземпляр каждому потребителюPerThread Один экземпляр внутри потокаPooled Определенное количество экземпляров, предоставляемое по мере освобожденияPerWebRequest Один экземпляр, предоставляемый всем потребителям в пределах одного запроса к Web-серверуPerGraph Один экземпляр на граф объектовScoped Один экземпляр внутри явно выделенного участка кодаLazy Transient, но инициализируемый не при разрешении зависимости, а при первом использовании
  26. 26. IoC – контейнеры Делают всё то же самое, что мы делаем руками Но большая часть их багов была уже поймана другими людьми Одно из главных требований к IoC контейнеру – 99% вашего кода не должно подозревать, что вы его используете Мне неизвестные причины, которые аргументировали бы НЕ использовать IoC контейнер
  27. 27. IoC-контейнеры – из чего выбрать?Ну, например… AutoFac Castle Windsor Dynamo.Ioc Funq Hiro LightCore LightInject LinFu Munq Ninject Petite Simple Injector Spring.NET StructureMap TinyIoc Unity
  28. 28. Castle Windsor Один из старейших IoC-контейнеров для .NET Текущая версия – 3.0.4001 Поддерживает конфигурирование из кода (FluentAPI), конфигурирование из XML и конфигурирование согласно конвенциям Отличные возможности для отладки – полная диагностическая информация о зарегистрированных классах и интерфейсах Концепция установщиков (Installer), позволяющая разносить регистрационный код для компонентов Поддержка абстракций логирования Поддержка Interception Поддержка авто-реализации фабрик
  29. 29. ДемоРегистрация и разрешениезависимостей
  30. 30. Перехват (Interception) вызовов Один из подходов к реализации cross-cutting concerns (вещей, которые используются во всех слоях вашего приложения – таких как логирование, проверка безопасности, кэширование и т.п.) Разновидность аспектного программирования Позволяет выполнять действия до или после вызовов методов у зависимостей, а также обрабатывать результат выполнения Сходен с Декоратором, но отсутствует необходимость дублировать код для каждого интерфейса и метода в интерфейсе
  31. 31. ДемоInterception в Castle Windsor
  32. 32. Фабрики в Castle Windsor Interface-based Factories – на основе интерфейса Castle Windsor сам генерирует фабрику Delegate-based Factories – можно зарегистрировать делегат типа Func<TResult>, который будет играть роль фабричного метода
  33. 33. ДемоФабрики в Castle Windsor
  34. 34. Отдельные темы для обсуждения Constructor Over-Injection public HomeController(IBookRepository rep, ICurrentUser user, ICurrencyFormatter formatter, IDateTimeProvider dateTimeProvider, IBookReturnmentPolicy policy, IBookOrderService bookOrderService, IBookSearchService bookSearchService, IScheduler scheduler, IEmailService emailService, ISmsSender smsSender){ … } Работа с IDisposable-зависимостями Круговая зависимость
  35. 35. Реальная жизнь На примере сайт GetDev.NET ASP.NET MVC 3 Castle Windsor Так и не удалось добиться единого Composition Root – CustomRoleProvider создается средой исполнения и не имеет возможности вставки зависимостей Используем Service Locator ;) Для доступа к данным – абстракция над Linq to Sql interface IUnitOfWork : IDisposable{ ITable<User> Users{ get; set; } … } Создаётся абстрактной фабрикой Декоратор вокруг IAccountService – кэширование ролей пользователя
  36. 36. Вопросы? Внимательно слушаю!  Андрей Кулешов «Деловые решения» Директорakuleshov@solforbiz.com akuleshov.tulahttp://www.solforbiz.comСпециально для http://GetDev.NET
  37. 37. Интересное чтение Dependency Injection in .NET by Mark Seemann http://manning.com/seemann/ Castle Windsor homepage http://stw.castleproject.org/Windsor.MainPage.ashx Krzysztof Koźmics blog http://kozmic.pl/ Сравнение производительности IoC-контейнеров http://www.palmmedia.de/Blog/2011/8/30/ioc-container- benchmark-performance-comparison Сравнение функциональности некоторых IoC-контейнеров http://code.google.com/p/net-ioc-frameworks/
  38. 38. Интересное видео IoC Container usage: Patterns and anti-pattern (Krzysztof Koźmic) http://kozmic.pl/presentations/ Inversion of Control/Dependency Injection Pattern (Hammet Verissimo & Michael Puleio) http://channel9.msdn.com/posts/PP-Symposium-2010- Inversion-of-ControlDependency-Injection-Pattern- Hammet-Verissimo--Michael-Puleio Channel 9 http://channel9.msdn.com/ Текстовое поле “Search” –> “Dependency Injection” || “Inversion of Control” -> Enter

×