Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

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

Podobne prezentacje


Prezentacja na temat: "Adam Suwała. Agenda: Dependency Injection - trochę podstaw Kontenery DI - masz problem, weź framework Service Locator - anti-pattern Do-It-Yourself Dependency."— Zapis prezentacji:

1 Adam Suwała

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

3

4 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. 4

5 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) 5

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

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

8 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); } //… } 8

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

10

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

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

13 Co fajnego potrafią robić kontenery DI? 13

14 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; } /*…*/ } 14

15 Kaskada zależności – jak złożyć? class UzycieKontenera { void Przyklad() { Kontener. Register () ; //… var mail = Kontener. Resolve () ; //… } 15

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

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

18 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 18

19

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

21

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

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

24 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; } } 24

25 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 } 25

26 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); } 26

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

28 Co zrobić ze skomplikowanymi przypadkami? 28

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

30 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) { /*…*/ } } 30

31 Uchwyty do obiektów w Scope 31

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

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

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

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

36 Jeszcze raz: konsekwencja w stosowaniu DI. 36

37 Mniej lub prostsze Mocki w testach jednostkowych. 37

38 Problem z kontekstami. 38

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

40 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; } 40

41 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; } //… } 41

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

43 Para Scope – Injector dla Komponentu class ComponentScope { internal readonly ScopeCache KlientSmtpCache = new ScopeCache (); internal readonly ScopeCache KlientTcpCache = new ScopeCache (); } 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()); } 43

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

45 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()); } 45

46 Pytania? 46

47 Źródła testy wydajnościowe kontenerów 47


Pobierz ppt "Adam Suwała. Agenda: Dependency Injection - trochę podstaw Kontenery DI - masz problem, weź framework Service Locator - anti-pattern Do-It-Yourself Dependency."

Podobne prezentacje


Reklamy Google