dependency injection

28
Dependency Injection Ať se postará někdo jiný, najmeme si programátory z Číny. Čuníkům vstup zakázán

Upload: orrin

Post on 20-Jan-2016

34 views

Category:

Documents


0 download

DESCRIPTION

Dependency Injection. Ať se postará někdo jiný, najmeme si programátory z Číny. Čuníkům vstup zakázán. Co budeme dneska dělat?. Zopakujeme si základní principy DI. Dozvíme se, jak může DI usnadnit programování. Ukážeme si, jak psát přehlednější a čitelnější kód. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Dependency Injection

Dependency InjectionAť se postará někdo jiný,

najmeme si programátory z Číny.

Čuníkům vstup zakázán

Page 2: Dependency Injection

Co budeme dneska dělat?Zopakujeme si základní principy DI.Dozvíme se, jak může DI usnadnit programování.Ukážeme si, jak psát přehlednější a čitelnější kód.Předvedeme si, jak se zbavit skrytých závislostí v

kódu a statického volání.Vše si demonstrujeme na příkladu z praxe, který si

společně zkritizujeme a opravíme.

V čem je to dobré?Minimálně se vyznáte ve vlastním kódu, i když se na

něj podíváte třeba za půl roku.

Page 3: Dependency Injection

Dependency InjectionJak poznám, že je třída závislá na jiné třídě?Co je to skrytá závislost?V čem nám DI pomáhá?Jaké znáte typy DI?

Dependency Injection ≠ čistý kód

DI + ≠ jen k němu vede

Page 4: Dependency Injection

Dependency InjectionVychází z návrhového vzoru Inversion of

Control.Odebírá třídám odpovědnost za vytváření

objektů, na kterých jsou závislé.Řízení je delegováno na nadřazený objekt.

Page 5: Dependency Injection

Klasický přístuppublic class Computer() {

private OsuNetwork network;

public Computer() {this.network = new OsuNetwork();

}}

Připojení k síti je služba, ne součást počítače.

Vzniká připojení k síti uvnitř počítače?

Page 6: Dependency Injection

Použití DIpublic class Computer() {

private OsuNetwork network;

// Constructor Injectionpublic Computer(OsuNetwork network) {this.network = network;}

// Setter Injectionpublic void setOsuNetwork(OsuNetwork network) {this.network = network;}

}

Kde seženu připojení k síti?„Ať se postará někdo jiný.“

Výrobce počítače se nemusí starat o připojení k síti, to řeší uživatel počítače (třídy počítač)

Page 7: Dependency Injection

Použití DI a rozhranípublic class Computer() {

private Network network;

// Constructor Injectionpublic Computer(Network network) {

this.network = network;}

// Setter Injectionpublic void setNetwork(Network network) {

this.network = network;}

}

Page 8: Dependency Injection

Dependency InjectionZávislost na jiných objektech jasně

deklarujeme v konstruktoru třídy nebo v jejich metodách.

Použití operátoru new uvnitř třídy je skrytá závislost.

Použití statického volání uvnitř třídy je skrytá závislost.

Výjimku tvoří primitivní typy a nativní třídy jazyka.new Class() Class.getInstance()

Page 9: Dependency Injection

Homer a závislosti

Page 10: Dependency Injection

Příklad na cvičeníPříklad ke cvičení je ke stažení na následující

adresehttp://tinyurl.com/mo4omp3

Page 11: Dependency Injection

Příklad na cvičenípublic class Application {

public Application() {Article article = new Article();article.setHeadline("Nadpis článku");article.setText("Text článku");article.save();

}}

Kam se článek uloží? Do souboru nebo do databáze?Jakou databázi používám?Jaké jsou parametry připojení?

Page 12: Dependency Injection

Já myslel/a, že to víš …Když něco potřebuju, tak si o to řeknu!Třída Article nemá žádné viditelné závislosti, ale

opravdu je nemá?Co se stane, když smažeme všechny ostatní třídy?

article->save(); // ERROR: Class MysqlStorage not found// ERROR: Class DatabaseConfig not found

Kdo by to čekal?

Page 13: Dependency Injection

Statické peklo v akcipublic class Article { private String headline; private String text; public void save() { MysqlStorage storage = MysqlStorage.getConnection(); storage.executeQuery("INSERT INTO articles…“); }}

Jaký návrhový vzor jsme použili? Nápověda: Class.getInstance();

Jedná se o porušení DI? Jaké je řešení?

Page 14: Dependency Injection

Řešení?public class Article { private String headline; private String text; public void save(MysqlStorage storage) {

storage.executeQuery("INSERT INTO articles…“);

}}Bude to fungovat? Co ještě musíme upravit?

Page 15: Dependency Injection

Zase o krok dále…Třída MysqlStorage je singleton. Převedeme ji na

klasickou třídu s veřejným konstruktorem.

public MysqlStorage() { DatabaseConfig config = new DatabaseConfig(); this.server = config.getServer();

// some code }

Je to v pořádku?Jsou všechny závislosti nahlášeny?

Page 16: Dependency Injection

Je to v pořádku? public MysqlStorage(DatabaseConfig config) {

this.server = config.getServer();// some code

}

Page 17: Dependency Injection

K zamyšlení …public class Article { private String headline; private String text; public void save(MysqlStorage storage) {

storage.executeQuery("INSERT INTO articles…“); }}

Je správné, aby třída Article věděla o struktuře DB?Co když budeme chtít uložit článek do souboru?

Page 18: Dependency Injection

Upravte kódpublic class Article { private String headline; private String text; public void save(Storage storage) {

storage.save(this); }}

Nesmíte zasáhnout do třídy MysqlStorage ani FileStorage

Page 19: Dependency Injection

Jak zajistit společné rozhraní? public class FileStorage { public void save(Article article) { System.out.println("Article was saved to file"); }}

public class MysqlStorage { public void executeQuery(String query) { System.out.println("Record was saved to database

(" + query + ")"); } }

Page 20: Dependency Injection

Použijeme adapterNávrhový vzor adaptér použijeme, pokud

potřebujeme, aby třída měla jiné rozhraní než to, které právě má.

Adaptér slouží jako prostředník mezi prostředím, které požaduje nějaké rozhraní, a třídou, jejíž rozhraní neodpovídá požadovanému. Umožňuje tedy spolupráci třídám, které by spolu jinak nespolupracovaly.

Page 21: Dependency Injection

Je to lepší? public Application() { Article article = new Article(); article.setHeadline("Nadpis článku"); article.setText("Text článku"); DatabaseConfig config = new DatabaseConfig(); MysqlStorage mysqlStorage = new

MysqlStorage(config); DatabaseStorage databaseStorage = new

DatabaseStorage(mysqlStorage); article.save(databaseStorage); }

Page 22: Dependency Injection

Sestavení závislostí pomocí containeru

Application

DI container

Page 23: Dependency Injection

DI container@Inject – ohlášení DI containeru, že má

obsloužit třídu.@Singleton – označení třídy jako singleton@ImplementedBy(ServiceImplementation.cla

ss)

Page 24: Dependency Injection

S použitím DI containeru @Injectpublic Application(Article article, Storage

storage) { article.setHeadline("Nadpis článku"); article.setText("Text článku"); article.save(storage); }

Page 25: Dependency Injection

ÚkolVytvořte jinou třídu, která má závislost na

rozhraní Storage.Přihlašte se k závislosti a sledujte v konzoli,

kolikrát se vytvoří připojení k DB.Jak použít singleton spolu s DI?

Page 26: Dependency Injection

A jak to dopadlo se singletonem?@Inject@Singletonpublic DatabaseStorage(MysqlStorage

storage) { this.storage = storage;}

Hurá, singleton se vrátil!Win: databázové připojení se vytvoří jen jednou.Win: žádné skryté závislosti.

Page 27: Dependency Injection

Rekapitulace: proč zvolit DI?Jasné vazby mezi objekty,pravdivý a předvídatelnější kód,přehlednější, lépe upravitelný,žádné statické volání,znovu použitelnost kódu,mnohem lepší testovatelnost.

Page 28: Dependency Injection

Zvládli jsme to!