ioc and .net

30
IoC & .NET (Inversion of Control & .NET) Jaromír Solař [email protected]

Upload: jaromir-solar

Post on 18-Jul-2015

186 views

Category:

Technology


1 download

TRANSCRIPT

IoC & .NET(Inversion of Control & .NET)

Jaromír Solař[email protected]

Hello World

public class HelloWorldClass{ public void PrintMessage() { Console.WriteLine("Hello World"); }}

Co je na tom špatně?

Nic, ale− je úzce svázáno s třídou Console− při změně způsobu výstupu musíme překódovat− nemožnost změny implementace za běhu− obtížná testovatelnost

Určitě se toho najde víc...

Co s tím?

Zamyslíme se Napíšeme do googlu dotaz „Hello World problem” Přečteme si nějakou knížku o programování Zkusíme si najít jinou práci

Přečteme si dobrou knížku o programování...

Inversion of Control

IoC není návrhový vzor, je to princip Přístup pro navrhování znovu-použitelných komponent Uvolnění vazeb mezi komponentami

− Komponenta se zaměřuje jen na svůj úkol− Komponenta má definované rozhraní− Pro svoji činnost může využívat jiné komponenty− Lze jí zaměnit za jinou se stejným rozhraním

Zjednodušuje testovatelnost

Což takhle nějaký příklad?

Delegates (callbacks)

public delegate void OutputService(String message);

public class HelloWorldClass{ public void PrintMessage(OutputService service) { service("Hello World"); }}

public class ConsoleOutputService{ public static void Write(String message)

{ Console.WriteLine(message); }}

HelloWorldClass helloWorld = new HelloWorldClass();helloWorld.PrintMessage( new OutputService(ConsoleOutputService.Write));

helloWorld.PrintMessage(ConsoleOutputService.Write);

helloWorld.PrintMessage( delegate(String message) { Console.WriteLine(message); });

helloWorld.PrintMessage(message => Console.WriteLine(message) );

Multicast delegate

OutputService outputService = new OutputService( delegate(String message) { /* Write to console */ });

outputService += new OutputService( delegate(String message) { /* Send email */ });

HelloWorldClass helloWorld = new HelloWorldClass();helloWorld.PrintMessage(outputService);

Events

Spouštěné na základě nějaké akce− např. stisknutí tlačítka nebo „tik” časovače

Podle konvence, události by měli mít 2 parametry:− sender – objekt, který událost posílá− argumenty – data související s událostí (dle konvence

by to měl být potomek třídy EventArgs) Hojně používáno v uživatelském rozhraní

public delegate void WriteMessageHandler( object sender, string message);

public class HelloWorldClass{ public event WriteMessageHandler WriteMessageEvent;

public void PrintMessage() { if (WriteMessageEvent != null) WriteMessageEvent(this, "Hello World"); }}

HelloWorldClass helloWorld = new HelloWorldClass();helloWorld.WriteMessageEvent += delegate(object sender, string message) { /* -1- */ };helloWorld.WriteMessageEvent += delegate(object sender, string message){ /* -2- */ };helloWorld.PrintMessage();

Asynchronous Delegates

Asynchronní delegáty lze volat pomocí BeginInvoke/EndInvoke

public class HelloWorldClass{ public void PrintMessage(OutputService service) { service.BeginInvoke("Hello World", null, null); }}

Predefined delegates

Delegáti nevracející hodnotu

public delegate void Action()public delegate void Action<in T>(T obj)

Delegáti vracející hodnotu

public delegate TResult Func<out Tresult>()public delegate TResult Func<in T, out TResult>(T arg)…

public delegate bool Predicate<in T>(T obj)

A jak to bude vypadat v HelloWorld?

public class HelloWorldClass{ public void PrintMessage(Action<String> service) { service("Hello World"); }}

HelloWorldClass helloWorld = new HelloWorldClass();helloWorld.PrintMessage( delegate(String message) { Console.WriteLine(message); });

Více o delegátech

Další téma na IT Pivo ;-) C# 3.0 Cookbook, Third Edition Chapter 9: Delegates, Events, and Lambda

Expressions

http://msdn.microsoft.com/en-us/library/orm-9780596516109-03-09.aspx

Interface

public interface IOutputService{ void Write(String message);}

public class ConsoleOutputService : IOutputService{ public void Write(string message) { Console.WriteLine(message); }}

Service locator

public class ServiceLocator{ public static IOutputService GetOutputService() { return new ConsoleOutputService(); }}

public class HelloWorldClass{ public void PrintMessage() { IoutputService service = ServiceLocator.GetOutputService(); service.Write("Hello World"); }}

Service locator

Klady Skrytí rozhraní od implementace Run-time záměna implementace

Zápory Singleton Pro rozsáhlé systémy obsahuje hodně metod, nebo se musí sepatovat do více tříd Komponenty mají závislost na service locator Horší testovatelnost

Dependency Injection

Asi nejpoužívanější vzor pro IoC Komponenta zná vnější svět jen dle rozhraní Implementace rozhraní dostává zvenčí

Způsoby nastavení implementací rozhraní− Constructor injection− Setter injection− Method injection− Interface injection

Constructor Injection

public class HelloWorldClass{ private IOutputService service;

public HelloWorldClass(IOutputService service) { this.service = service; }

public void PrintMessage() { service.Write("Hello World"); }}

Setter Injection

public class HelloWorldClass{ public IOutputService Service { get; set; }

public void PrintMessage() { Service.Write("Hello World"); }}

Method Injection - I

public class HelloWorldClass{ public void PrintMessage(IOutputService service) { service.Write("Hello World"); }}

Method Injection - II

public class HelloWorldClass{ private IOutputService service;

public void Init(IOutputService service) { this.service = service; }

public void PrintMessage() { service.Write("Hello World"); }}

Interface Injection

public interface IOutputServiceInitializer{ void Init(IOutputService service);}

public class HelloWorldClass : IOutputServiceInitializer{ private IOutputService service;

public void Init(IOutputService service) { this.service = service; } ...}

Dependency Injection

Klady Komponenta dělá jen svou práci Komponenta s okolím komunikuje pouze přes rozhraní Implementace rozhraní jsou dodávány za běhu Testovatelnost

Zápory Horší hledání integračních chyb Možný nižší výkon (injekce, přetypování...)

IoC Containers

Komponenta zjednodušující DI Konfigurace závislostí (kód, soubor...) Vytváření objektů Doplnění závislostí Spravuje živostnost objektů

− Always New− Container Lifetime− Thread Lifetime− Time Lifetime− Request / Session

A někteří dělají ještě více

Příklad práce s IoC Container

public class Container{ public void Register<T, TImpl>() { … } public T Resolve<T>() { … }}

Container container = new Container();container.Register<IOutputService, ConsoleOutputService>();container.Register<HelloWorldClass, HelloWorldClass>();

HelloWorldClass hello = container.Resolve<HelloWorldClass>();hello.PrintMessage();

Jaký způsob injection používá tento container?

Jaký IoC Container vybrat

Funkčnost Konfigurace Výkon Napsat si vlastní

http://www.palmmedia.de/Blog/2011/8/30/ioc-container-benchmark-performance-comparison

Tips

Používat DI a Constructor Injection Používat „vhodný” Container Neodkazovat z komponent na Container (pokud potřebuji

více instancí, nebo nové instance, použít delegáta)

The last example

public interface IA {}

public class B{ public B(Func<IA> getA, Action<IA> releaseA) { this.getA = getA; this.releaseA = releaseA; } public void Process() { IA a = getA(); // use a releaseA(a); }}

Děkuji, že jste neusnuli