Dependency injection на примере unity и n inject

26
DEPENDENCY INJECTION НА ПРИМЕРЕ UNITY И NINJECT Калита Роман TaskManagementSoft Company Logo

Transcript of Dependency injection на примере unity и n inject

Page 1: Dependency injection на примере unity и n inject

DEPENDENCY INJECTION НА ПРИМЕРЕ UNITY И NINJECT

Калита РоманTaskManagementSoft

Company Logo

Page 2: Dependency injection на примере unity и n inject

ПЛАН

• Что такое Dependency Injection?• Как проблемы решает и какие преимущества

дает при проектировании• Какие есть формы DI• DI контейнеры в .NET

Page 3: Dependency injection на примере unity и n inject

Качественный код/системаРасширяемый

(extensibility)

Легко сопровождаем

ый (maintainability)

Простой (simplicity)

Читабельный (readability)

Тестируемый (testability)

Код

Page 4: Dependency injection на примере unity и n inject

Некоторые проблемы при проектировании приложений

По версии GoF

Веде

т к

силь

ной

связ

анно

сти

При создании объекта явно указывается класс

Зависимость от апаратных/программных

платформ

Зависимость от представления или

реализации объекта

Зависимость от алгоритмов

Page 5: Dependency injection на примере unity и n inject

Сильносвязанные системы

Page 6: Dependency injection на примере unity и n inject

Сильносвязанные системыподдерживать

расширять

тестироватьпонимать

использовать снова

О каких качествах кода может идти речь?

сложно

Page 7: Dependency injection на примере unity и n inject

Уменьшаем связанность

Абстрактная фабрика

(Abstract factory)

Фабричный метод (Factory method)

Локатор сервиса (Service Locator)

Внедрение зависимостей (Dependency

Injection)

Page 8: Dependency injection на примере unity и n inject

Фабрика, Локатор, Метод

Клиент Фабрика, Локатор, Метод

MyClassIMyInterface

Запрашивает IMyInterface

Создает MyClass

Реализует IMyInterface

Page 9: Dependency injection на примере unity и n inject

Dependency Injection

Клиент DI контейнер

КонфигурацияMyClass :

IMyInterface

запрашивает

читаетсоздает/возвращает

Обявляет зависимости

внедряет

MyClass : IMyInterface

Page 10: Dependency injection на примере unity и n inject

Что такое Dependency Injection?Инверсия зависимостей == Обращение контроля == Внедрение зависимостей == Dependency injection

Это принцип в объектно ориентированом программировании, который означает:

• Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракции.

• Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

Цель:• Уменьшить связность

Page 11: Dependency injection на примере unity и n inject

Пример связанного приложенияpublic class Program{ public static void Main(string[] args) { var orderManager = new OrderManager(); orderManager.ProcessOrders(); }}

OrderManager OrdersQueue

OrdersProcessor

Page 12: Dependency injection на примере unity и n inject

Пример связанного приложения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 и n inject

Пример связанного приложения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 и n inject

Проблемы в примере

[TestClass] public class OrderManagerTests { [TestMethod] public void should_process_orders() { var orderManager = new OrderManager(); orderManager.ProcessOrders(); } }

• Тестируемость

• Привязан к конкрентым сущностям, знает о них и создает их

Page 15: Dependency injection на примере unity и n inject

Применяем принцип вручную

public interface OrdersProcessor { void Process(Order order); }

public interface IOrdersQueue { List<Order> GetPendingOrders(); }

• Будем привязыватся к интерфейсам

• Вынесемзависимости в readonly поля класса, которые будут заполнятся из вне при инстанциировании объекта

Page 16: Dependency injection на примере unity и n inject

Применяем принцип вручную 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 и n inject

Применяем используя контейнер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 и n inject

Ручное DI vs Контейнер• Оба варианта решают проблему класса с

высокой связанностью

• Если вручную, выполнение лишней работы по созданию и наполнению зависимостями

• Если используюя контейнер досутпны возможности по «автоматическому» или «условному» наполнению зависимостями, не требующие никаких усилий

• Время жизни объектов также должно гибко контролироватся, вручную – «лишняя работа»

Page 19: Dependency injection на примере unity и n inject

Формы 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 и n inject

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 и n inject

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 и n inject

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 и n inject

“Продвинутая” конфигурация

• Условный биндинг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 и n inject

Преимущества от использования Dependecy Injection• Разделение конфигурирования связей и

использования объектов• Уменьшается связывание

Абстрактные интерфейсы не меняютсяКонкретные объекты реализуют эти интерфейсыКонкретные объекты проще заменить

• Увеличение мобильности модулей

• Улучшение изоляции объектовУменьшается связностьУвеличивается тестируемостьУвеличивается удобство в поддержке

Page 25: Dependency injection на примере unity и n inject

Ссылки• 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 и n inject

Спасибо за внимание:)