Adam Suwała DIY - DI.

Slides:



Advertisements
Podobne prezentacje
I część 1.
Advertisements

Java Data Objects.
Znaki informacyjne.
Wprowadzenie do informatyki Wykład 6
1 Ochrona środowiska – historia od PLAN 1.Wprowadzenie 2.Przegląd wydarzeń od 1972 roku 3.Podsumowanie 4.Literatura.
Java Server Faces Tomasz Nowak.
ALLEGRO PIERWSZA GRA: WYŚCIG
C++ w Objectivity Marcin Michalak s1744. Pomocne pakiety: Data Definition Language (DDL). Standard Template Library (STL). Active Schema.
Liczby pierwsze.
Domy Na Wodzie - metoda na wlasne M
1 mgr inż. Sylwester Laskowski Opiekun Naukowy: prof. dr hab. inż. Andrzej P. Wierzbicki.
Java vs C# Michał Prządka Tomasz Nowak
GUI Struktury Spotkanie integracyjne Nazwa wydziału: EAIiE Nazwa katedry: Informatyka Miejsce i data prezentacji: Kraków,
Ksantypa2: Architektura
Systemy operacyjne Copyright, 2000 © Jerzy R. Nawrocki Wprowadzenie do informatyki.
PREPARATYWNA CHROMATOGRAFIA CIECZOWA.
Ministerstwo Gospodarki Poland'sexperience Waldemar Pawlak Deputy Prime Minister, Minister of Economy March 2010.
Testowanie oprogramowania metodą badania pokrycia kodu
Łukasz Monkiewicz.
Współprogramy Plan: Motywacja Składnia Scenariusz obiektu współprogramu Przykłady Producent – konsument ( instrukcja attach ) Czytelnik -pisarze ( instukcja.
142 JAVA – sterowanie i wątki public class A20 extends javax.swing.JApplet implements ActionListener { private int licznik = 0; private JTextField t =
Klasyfikacja systemów
Transformacja Z (13.6).
Pytania konkursowe.
Tytuł prezentacji Warszawa, r..
Efektywność zdawania egzaminu zawodowego w ZSP w Bytowie w roku szkolnym 2008/2009.
Ogólnopolski Konkurs Wiedzy Biblijnej Analiza wyników IV i V edycji Michał M. Stępień
REKURENCJA.
Raport z badań termowizyjnych – RECTICEL Rys. 1a. Rozdzielnia RS14 Temperatura maksymalna 35,27 o C Rys. 1b. Rozdzielnia RS14 (wizyjny) 3.
Krzysztof Manuszewski
Anna Nowak Przedszkole publiczne im. Kubusia puchatka w zabełkowie
1 ANALIZA STANU BEZROBOCIA NA TERENIE MIASTA I GMINY GOŁAŃCZ ANALIZA STANU BEZROBOCIA NA TERENIE MIASTA I GMINY GOŁAŃCZ ZA ROK 2004 ORAZ PORÓWNANIE Z LATAMI.
Galeria zdjęć Projekt edukacyjny „Wiem, co jem” realizowany w ramach
Asynchroniczność w Windows 8 Jakub Binkowski. O mnie Jakub Binkowski Lead.NET Developer.
1/34 HISTORIA BUDOWY /34 3/34 6 MAJA 2011.
KOLEKTOR ZASOBNIK 2 ZASOBNIK 1 POMPA P2 POMPA P1 30°C Zasada działanie instalacji solarnej.
ŻYWE JĘZYKI PROGRAMOWANIA LIVING IT UP WITH A LIVE PROGRAMMING LANGUAGE Sean McDirmid Ecole Polytechnique Fédérale de Lausanne (EPFL)
Analiza wpływu regulatora na jakość regulacji (1)
db4o Kacper Skory Marcin Talarek
Seminarium problemowe
PIO 2_2, Zofia Kruczkiewicz1 Wykład 2 – część druga Iteracyjno-rozwojowy cykl oprogramowania 2.
PIO. Autor -Zofia Kruczkiewicz1 Wykład 1-część druga Wstęp do inżynierii oprogramowania. Cykle rozwoju oprogramowania (część biznesowa aplikacji) iteracyjno-rozwojowy.
PIO. Autor -Zofia Kruczkiewicz1 Wykład 1-część druga Wstęp do inżynierii oprogramowania. Cykle rozwoju oprogramowania (część biznesowa aplikacji) iteracyjno-rozwojowy.
Podstawy programowania
Szkoła systemów społecznych. Istota, przedstawiciele, wyniki
MATURA 2007 raport ZESPÓŁ SZKÓŁ I PLACÓWEK KSZTAŁCENIA ZAWODOWEGO.
Koło emocji wg Plutchika (1980)
Projekt współfinansowany ze środków Unii Europejskiej w ramach Europejskiego Funduszu Społecznego Konferencja Elektroniczny Obieg Informacji w Firmie Łódź,
1. Pomyśl sobie liczbę dwucyfrową (Na przykład: 62)
Cz.8 Zdarzenia. Refleksja – przypomnienie Event Programowanie zdarzeniowe Do dzieła!
Warsztaty C# Część 2 Grzegorz Piotrowski Grupa.NET PO
Warsztaty C# Część 3 Grzegorz Piotrowski Grupa.NET PO
- powtórzenie wiadomości
Instrukcje sterujące: W instrukcjach sterujących podejmowane są decyzje o wykonaniu tych czy innych instrukcji programu. Decyzje te podejmowane są w zależności.
Wolfek,Mario, Kamila,Natalia i Zibi in Zachód słońca na Malcie przed imprą
-17 Oczekiwania gospodarcze – Europa Wrzesień 2013 Wskaźnik > +20 Wskaźnik 0 a +20 Wskaźnik 0 a -20 Wskaźnik < -20 Unia Europejska ogółem: +6 Wskaźnik.
TROCHĘ HISTORII Marek Zając PO CO UŻYWAĆ OPENCL? Marek Zając.
+21 Oczekiwania gospodarcze – Europa Grudzień 2013 Wskaźnik > +20 Wskaźnik 0 do +20 Wskaźnik 0 do -20 Wskaźnik < -20 Unia Europejska ogółem: +14 Wskaźnik.
1.
EcoCondens Kompakt BBK 7-22 E.
EcoCondens BBS 2,9-28 E.
Programowanie w języku C++
Testogranie TESTOGRANIE Bogdana Berezy.
Jak Jaś parował skarpetki Andrzej Majkowski 1 informatyka +
Kalendarz 2020.
Współrzędnościowe maszyny pomiarowe
Ankieta dotycząca kart bankomatowych i kont bankowych.
Elementy geometryczne i relacje
Strategia pomiaru.
Delegaty Delegat to obiekt „wiedzący”, jak wywołać metodę.
Zapis prezentacji:

Adam Suwała DIY - DI

Agenda: Dependency Injection - trochę podstaw Kontenery DI - masz problem, weź framework Service Locator - anti-pattern Do-It-Yourself Dependency Injection

Dependency Injection - trochę podstaw

Definicje z WIKI • Wstrzykiwanie zależności (Dependency Injection, DI) – wzorzec projektowy i wzorzec architektury oprogramowania polegający na usuwaniu bezpośrednich zależności pomiędzy komponentami na rzecz architektury typu plug-in. • Odwrócenie sterowania (Inversion of Control, IoC) – paradygmat polegający na przeniesieniu na zewnątrz komponentu (np. obiektu) odpowiedzialności za kontrolę wybranych czynności.

Po co DI? sprawić żeby kod miał miej powiązań lub powiązania były „luźniejsze” (loose coupling). ułatwić testy jednostkowe kodu (automatyczne testy pojedynczych klas w izolacji od innych)

Rodzaje wstrzykiwania zależności: Constructor Injection Setter Injection Interface Injection

Jak to wygląda w praktyce? Tradycyjne podejście: class Mail { //… public bool Wyslij() var klientSmtp = new KlientSmtp(); return klientSmtp.Wyslij(adres, tytul, tresc); }

Podejście DI: class Mail { private readonly IKlientSmtp klientSmtp; public Mail(IKlientSmtp klientSmtp) this.klientSmtp = klientSmtp; } //… public bool Wyslij() var klientSmtp = new KlientSmtp(); return klientSmtp.Wyslij(adres, tytul, tresc);

Skąd w DI biorą się zależności? class Mail { private readonly IKlientSmtp klientSmtp; public Mail(IKlientSmtp klientSmtp) this.klientSmtp = klientSmtp; } //…

Kontenery - masz problem, weź framework

Frameworki DI dla .net, przykłady: • Autofac • Castle.Windsor • Ninject • Sprint.net • StructureMap • Unity

Świadomy wybór kontenera DI Różnice: • Składnia • Wsparcie dla różnych rozwiązań • Szybkość działania

Co fajnego potrafią robić kontenery DI?

Kaskada zależności – powiązania klas class KlientTcp : IKlientTcp { /*…*/ } class KlientSmtp : IKlientSmtp { private readonly IKlientTcp klientTcp; public KlientSmtp(IKlientTcp klientTcp) { this.klientTcp = klientTcp; } /*…*/ } class Mail { private readonly IKlientSmtp klientSmtp; public Mail(IKlientSmtp klientSmtp) { this.klientSmtp = klientSmtp;

Kaskada zależności – jak złożyć? class UzycieKontenera { void Przyklad() { Kontener.Register<IKlientTcp, KlientTcp>(); Kontener.Register<IKlientSmtp, KlientSmtp>(); //… var mail = Kontener.Resolve<Mail>(); }

Metody inicjowania kontenera Bezpośrednie rejestrowanie w kodzie Pliki konfiguracyjne Z użyciem refleksji

Czas życia obiektów Transient Singleton Thread Singleton Request Singleton

Dlaczego DI bez kontenera? Nie jest konieczny do robienia DI Może zaciemniać kod Rzeczywiste zależności mogą nie być tak proste jak w przykładach Może prowokować do robienie DI źle

Service Locator - anti-pattern

Jak wygląda wzorzec Service Locator: class Mail { //… public bool Wyslij() var klientSmtp = Kontener.Resolve<IKlientSmtp>(); return klientSmtp.Wyslij(adres, tytul, tresc); }

Do-It-Yourself Dependency Injection

„Chad Parry DIY-DI” – jak zrobić dobre DI bez kontenera.

DI powinniśmy używać konsekwentnie w całej aplikacji. DI to sposób myślenia

Scope – techniczna klasa, która ma przechowywać parametry konfiguracyjne i uchwyty do obiektów class ApplicationScope { private readonly string[] args; public ApplicationScope(string[] args) this.args = args; MaxX = 100; MaxY = 100; } public string[] Args { get { return args; } } public int MaxX { get; private set; } public int MaxY { get; private set; }

MainHelper – „biznesowo-pomocnicza” klasa, która umożliwia wstrzykiwanie zależności od samego startu programu class MainHelper { private readonly string[] args; private readonly IRobot robot; public MainHelper(string[] args, IRobot robot) this.args = args; this.robot = robot; } public void Run() // to co normalnie jest w main

Injector – techniczna klasa, której zadaniem jest składanie aplikacji i właściwe wstrzykiwanie zależności class ApplicationInjector { public MainHelper InjectMainHelper(ApplicationScope scope) return new MainHelper(scope.Args, InjectRobot(scope)); } private IRobot InjectRobot(ApplicationScope scope) return new Robot(scope.MaxX, scope.MaxY);

Start programu class Program { static void Main(string[] args) var scope = new ApplicationScope(args); new ApplicationInjector() .InjectMainHelper(scope) .Run(); }

Co zrobić ze skomplikowanymi przypadkami?

Fabryka – ale nie taka zwyczajna public class FabrykaRobotow { private readonly Func<IRobot> robotBuild; private readonly Func<IRobot> robotLatajacyBuild; internal FabrykaRobotow(Func<IRobot> robotBuild, Func<IRobot> robotLatajacyBuild) { this.robotBuild = robotBuild; this.robotLatajacyBuild = robotLatajacyBuild; } public IRobot ZbudujRobota() { bool decyzja = new Random().Next(1) == 0; if (decyzja) return robotBuild(); else return robotLatajacyBuild();

Użycie fabryki class ApplicationInjector { public MainHelper InjectMainHelper(ApplicationScope scope) { return new MainHelper( scope.Args, InjectFabrykaRobotow(scope).ZbudujRobota()); } private FabrykaRobotow InjectFabrykaRobotow(ApplicationScope scope) { return new FabrykaRobotow( () => InjectRobot(scope), () => InjectRobotLatajacy(scope)); private IRobot InjectRobot(ApplicationScope scope) { /*…*/ } private IRobot InjectRobotLatajacy(ApplicationScope scope) { /*…*/ }

Uchwyty do obiektów w Scope

Uchwyt do obiektu w Scope class ScopeCache<T> { private readonly object @lock = new object(); private volatile bool full; private T cache; public T Get(Func<T> initiator) { if (!full) { lock (@lock) { if (!full) { cache = initiator(); full = true; } return cache;

Użycie ScopeCache w Scope class ApplicationScope { //… public readonly ScopeCache<FabrykaRobotow> FabrykaRobotowCache = new ScopeCache<FabrykaRobotow>(); }

Inicjacja obiektu w Injector class ApplicationInjector { //… private FabrykaRobotow InjectFabrykaRobotow(ApplicationScope scope) return scope.FabrykaRobotowCache.Get(() => new FabrykaRobotow( () => InjectRobot(scope), () => InjectRobotLatajacy(scope) ) ); }

Uchwyt „per-wątek” public class ScopeThreadCache<T> { private readonly ThreadLocal<T> cache = new ThreadLocal<T>(); public T Get(Func<T> initiator) if (!cache.IsValueCreated) cache.Value = initiator(); } return cache.Value;

Jeszcze raz: konsekwencja w stosowaniu DI.

Mniej lub prostsze Mock’i w testach jednostkowych.

Problem z kontekstami.

Robot - wywołanie class ApplicationInjector { //… private IRobot InjectRobot(ApplicationScope scope) return new Robot(scope.MaxX, scope.MaxY); }

Robot – definicja klasy public class Robot : IRobot { private readonly int maxX; private readonly int maxY; internal Robot(int maxX, int maxY) { this.maxX = maxX; this.maxY = maxY; } public bool IdzDo(int x, int y) { // zrób co trzeba return true;

Jeżeli parametrów było by zbyt wiele public class Robot : IRobot { private readonly RobotLimits limits; internal Robot(RobotLimits limits) this.limits = limits; } //… public class RobotLimits public int MaxX { get; set; } public int MaxY { get; set; }

Komponenty aplikacji mogą mieć własną parę klas Scope-Injector.

Para Scope – Injector dla Komponentu class ComponentScope { internal readonly ScopeCache<KlientSmtp> KlientSmtpCache = new ScopeCache<KlientSmtp>(); internal readonly ScopeCache<KlientTcp> KlientTcpCache = new ScopeCache<KlientTcp>(); } class ComponentInjector public IKlientSmtp InjectKlientSmtp(ComponentScope scope) { return scope.KlientSmtpCache.Get(() => new KlientSmtp(InjectKlientTcp(scope))); private IKlientTcp InjectKlientTcp(ComponentScope scope) { return scope.KlientTcpCache.Get(() => new KlientTcp());

Podpięcie komponentu w ApplicationScope class ApplicationScope { //… public readonly ScopeCache<ComponentInjector> ComponentInjectorCache = new ScopeCache<ComponentInjector>(); public readonly ScopeCache<ComponentScope> ComponentScopeCache = new ScopeCache<ComponentScope>(); }

Użycie komponentu w ApplicationInjector class ApplicationInjector { //… private Mail InjectMail(ApplicationScope scope) { return new Mail(InjectKlientSmtp(scope)); } private IKlientSmtp InjectKlientSmtp(ApplicationScope scope) { return InjectComponentInjector(scope) .InjectKlientSmtp(InjectComponentScope(scope)); private ComponentInjector InjectComponentInjector(ApplicationScope scope) { return scope.ComponentInjectorCache.Get(() => new ComponentInjector()); private ComponentScope InjectComponentScope(ApplicationScope scope) { return scope.ComponentScopeCache.Get(() => new ComponentScope());

Pytania?

Źródła http://pl.wikipedia.org/wiki/Wstrzykiwanie_zale%C5%BCno%C5%9Bci http://www.martinfowler.com/articles/injection.html http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx http://philipm.at/2011/0808/ --- testy wydajnościowe kontenerów http://misko.hevery.com/2010/05/26/do-it-yourself-dependency-injection/ http://blacksheep.parry.org/wp-content/uploads/2010/03/DIY-DI.pdf