dependency injection на примере unity и ninject
DESCRIPTION
Dependency Injection на примере Unity и N Inject / DevCamp ВинницаTRANSCRIPT
![Page 1: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/1.jpg)
DEPENDENCY INJECTION НА ПРИМЕРЕ UNITY И NINJECT
Калита РоманTaskManagementSoft
Company Logo
![Page 2: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/2.jpg)
ПЛАН
• Что такое Dependency Injection?• Как проблемы решает и какие преимущества
дает при проектировании• Какие есть формы DI• DI контейнеры в .NET
![Page 3: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/3.jpg)
Качественный код/системаРасширяемый
(extensibility)
Легко сопровождаем
ый (maintainability)
Простой (simplicity)
Читабельный (readability)
Тестируемый (testability)
Код
![Page 4: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/4.jpg)
Некоторые проблемы при проектировании приложений
По версии GoF
Веде
т к
силь
ной
связ
анно
сти
При создании объекта явно указывается класс
Зависимость от апаратных/программных
платформ
Зависимость от представления или
реализации объекта
Зависимость от алгоритмов
![Page 5: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/5.jpg)
Сильносвязанные системы
![Page 6: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/6.jpg)
Сильносвязанные системыподдерживать
расширять
тестироватьпонимать
использовать снова
О каких качествах кода может идти речь?
сложно
![Page 7: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/7.jpg)
Уменьшаем связанность
Абстрактная фабрика
(Abstract factory)
Фабричный метод (Factory method)
Локатор сервиса (Service Locator)
Внедрение зависимостей (Dependency
Injection)
![Page 8: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/8.jpg)
Фабрика, Локатор, Метод
Клиент Фабрика, Локатор, Метод
MyClassIMyInterface
Запрашивает IMyInterface
Создает MyClass
Реализует IMyInterface
![Page 9: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/9.jpg)
Dependency Injection
Клиент DI контейнер
КонфигурацияMyClass :
IMyInterface
запрашивает
читаетсоздает/возвращает
Обявляет зависимости
внедряет
MyClass : IMyInterface
![Page 10: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/10.jpg)
Что такое Dependency Injection?Инверсия зависимостей == Обращение контроля == Внедрение зависимостей == Dependency injection
Это принцип в объектно ориентированом программировании, который означает:
• Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракции.
• Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Цель:• Уменьшить связность
![Page 11: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/11.jpg)
Пример связанного приложенияpublic class Program{ public static void Main(string[] args) { var orderManager = new OrderManager(); orderManager.ProcessOrders(); }}
OrderManager OrdersQueue
OrdersProcessor
![Page 12: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/12.jpg)
Пример связанного приложенияpublic class OrderManager { public void ProcessOrders() { var ordersQueue = new OrdersQueue(); IList<Order> orders = ordersQueue.GetPendingOrders(); if (orders.Count == 0) throw new EmptyOrdersQueueException(); var ordersProcessor = new ManualOrdersProcessor(); foreach (Order order in orders) { ordersProcessor.ProcessOrder(order); } } }
![Page 13: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/13.jpg)
Пример связанного приложенияpublic class OrderManager { public void ProcessOrders() { var ordersQueue = new OrdersQueue(); IList<Order> orders = ordersQueue.GetPendingOrders(); if (orders.Count == 0) throw new NoOrdersException(); var ordersProcessor = new ManualOrdersProcessor(); foreach (Order order in orders) { ordersProcessor.ProcessOrder(order); } } }
![Page 14: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/14.jpg)
Проблемы в примере
[TestClass] public class OrderManagerTests { [TestMethod] public void should_process_orders() { var orderManager = new OrderManager(); orderManager.ProcessOrders(); } }
• Тестируемость
• Привязан к конкрентым сущностям, знает о них и создает их
![Page 15: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/15.jpg)
Применяем принцип вручную
public interface OrdersProcessor { void Process(Order order); }
public interface IOrdersQueue { List<Order> GetPendingOrders(); }
• Будем привязыватся к интерфейсам
• Вынесемзависимости в readonly поля класса, которые будут заполнятся из вне при инстанциировании объекта
![Page 16: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/16.jpg)
Применяем принцип вручную public class OrderManager { private readonly IOrdersQueue ordersQueue; private readonly IOrdersProcessor ordersProcessor;
public OrderManager(IOrdersQueue ordersQueue, IOrdersProcessor ordersProcessor)
{ this.ordersProcessor = ordersProcessor; this.ordersQueue = ordersQueue; }
public void ProcessOrders() { IList<Order> orders = ordersQueue.GetPendingOrders();
if (orders.Count == 0) throw new NoOrdersException(); foreach (Order order in orders) { ordersProcessor.Process(order); } } }
![Page 17: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/17.jpg)
Применяем используя контейнерpublic class OrderManager{ [Inject] public IOrdersQueue ordersQueue { get; set; }
[Inject] public IOrdersProcessor ordersProcessor { get; set; }
public void ProcessOrders() { IList<Order> orders = ordersQueue.GetPendingOrders();
if (orders.Count == 0) throw new NoOrdersException(); foreach (Order order in orders) { ordersProcessor.Process(order); } } }
![Page 18: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/18.jpg)
Ручное DI vs Контейнер• Оба варианта решают проблему класса с
высокой связанностью
• Если вручную, выполнение лишней работы по созданию и наполнению зависимостями
• Если используюя контейнер досутпны возможности по «автоматическому» или «условному» наполнению зависимостями, не требующие никаких усилий
• Время жизни объектов также должно гибко контролироватся, вручную – «лишняя работа»
![Page 19: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/19.jpg)
Формы Dependecy Injection• Constructor Injection
• Property(Setter) Injection
• Method Injection
[Inject]public OrderManager(IOrdersQueue ordersQueue, IOrdersProcessor ordersProcessor){ this.ordersProcessor = ordersProcessor; this.ordersQueue = ordersQueue;}
[Inject]public IOrdersProcessor ordersProcessor { get; }
[Inject]void DoSomeTask(IOrdersQueue orederQueue){ // ...}
![Page 20: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/20.jpg)
Dependecy Injection контейнеры• StructureMap (AltDotNet)http://structuremap.sourceforge.net/Default.htm
• Castle Windsor (AltDotNet)http://www.castleproject.org/container/index.html
• Unity (Microsoft P&P)http://www.codeplex.com/unity
• Ninject (open source)http://ninject.org
• Много других (LinFu, например)
![Page 21: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/21.jpg)
Dependecy Injection используя nInject
• Необходимо определить конфигурациюpublic class OrdersModule : NinjectModule{ public override void Load() { Bind<IOrdersQueue>().To<OrdersQueue>(); Bind<IOrdersQueue>().To<OrdersQueue>(); Bind<IOrdersProcessor>().To<ManualOrdersProcessor>(); Bind<OrderManager>().ToSelf(); }}• Теперь можно использовать, например
property injection[Inject]public IOrdersQueue ordersQueue { get; set; }
![Page 22: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/22.jpg)
Dependecy Injection используя Unity
• Необходимо определить конфигурацию var unityContainer = new UnityContainer() .RegisterType<IOrdersProcessor, ManualOrdersProcessor>() .RegisterType<IOrdersQueue, OrdersQueue>();
OrdersManager manager = unityContainer.Resolve<OrdersManager>();manager.ProcessOrders();
• Теперь можно использовать, например property injection
[Dependency]public IOrdersQueue ordersQueue { get; set; }
![Page 23: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/23.jpg)
“Продвинутая” конфигурация
• Условный биндингBind<IOrdersProcessor>().To<ManualOrdersProcessor>().WhenTargetHas<MyAttribute>();Bind<IOrdersProcessor>().To<ManualOrdersProcessor>()
.Only(When.Context.Target.Name.BeginsWith("Manual"));
var container = new UnityContainer() .RegisterType<IOrdersQueue, OrdersQueue>()
.RegisterType<IOrdersProcessor, ManualOrdersProcessor>(new InjectionConstructor(10));
• Время жизни
Bind<IOrdersProcessor>().To<ManualOrdersProcessor>().InSingletonScope();Bind<IOrdersProcessor>().To<ManualOrdersProcessor>().InThreadScope();
var container = new UnityContainer() .RegisterType<IOrdersProcessor,
ManualOrdersProcessor>(new ContainerControlledLifetimeManager())
![Page 24: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/24.jpg)
Преимущества от использования Dependecy Injection• Разделение конфигурирования связей и
использования объектов• Уменьшается связывание
Абстрактные интерфейсы не меняютсяКонкретные объекты реализуют эти интерфейсыКонкретные объекты проще заменить
• Увеличение мобильности модулей
• Улучшение изоляции объектовУменьшается связностьУвеличивается тестируемостьУвеличивается удобство в поддержке
![Page 25: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/25.jpg)
Ссылки• http://martinfowler.com/articles/injection.html
• http://www.objectmentor.com/resources/articles/dip.pdf
• http://msdn.microsoft.com/en-us/library/aa973811.aspx
• http://ninject.org/
• http://unity.codeplex.com
![Page 26: Dependency Injection на примере Unity и NInject](https://reader031.vdocuments.mx/reader031/viewer/2022013105/5555ccffd8b42aaf158b4b32/html5/thumbnails/26.jpg)
Спасибо за внимание:)