2. Hello World
public class HelloWorldClass
{
public void PrintMessage()
{
Console.WriteLine("Hello World");
}
}
3. 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...
4. 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í...
5. 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?
6. Delegates (callbacks)
public delegate void OutputService(String message);
public class HelloWorldClass
{
public void PrintMessage(OutputService service)
{
service("Hello World");
}
}
7. 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) );
8. 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);
9. 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í
10. 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();
11. Asynchronous Delegates
Asynchronní delegáty lze volat pomocí BeginInvoke/EndInvoke
public class HelloWorldClass
{
public void PrintMessage(OutputService service)
{
service.BeginInvoke("Hello World", null, null);
}
}
12. 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)
13. 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); });
14. 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
15. Interface
public interface IOutputService
{
void Write(String message);
}
public class ConsoleOutputService : IOutputService
{
public void Write(string message)
{
Console.WriteLine(message);
}
}
16. 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");
}
}
17. 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
18. 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
19. Constructor Injection
public class HelloWorldClass
{
private IOutputService service;
public HelloWorldClass(IOutputService service)
{
this.service = service;
}
public void PrintMessage()
{
service.Write("Hello World");
}
}
20. Setter Injection
public class HelloWorldClass
{
public IOutputService Service { get; set; }
public void PrintMessage()
{
Service.Write("Hello World");
}
}
21. Method Injection - I
public class HelloWorldClass
{
public void PrintMessage(IOutputService service)
{
service.Write("Hello World");
}
}
22. Method Injection - II
public class HelloWorldClass
{
private IOutputService service;
public void Init(IOutputService service)
{
this.service = service;
}
public void PrintMessage()
{
service.Write("Hello World");
}
}
23. Interface Injection
public interface IOutputServiceInitializer
{
void Init(IOutputService service);
}
public class HelloWorldClass : IOutputServiceInitializer
{
private IOutputService service;
public void Init(IOutputService service)
{
this.service = service;
}
...
}
24. 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í...)
25. 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
26. 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?
27. 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
28. 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)
29. 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);
}
}
Dependency Injection
IoC je koncept – co chceme dosáhnout
Poskytují více obecnosti než delegáti
Společné vlastnosti s delegáty
Oba obsahují pouze deklaraci typu
Různé metody/třídy je můžou implementovat
Oba podporují run-time polymorfismus