dependency injection

Post on 20-Jan-2016

32 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

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

Dependency InjectionAť 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.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.

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

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.

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?

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

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

}

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

Homer a závislosti

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

adresehttp://tinyurl.com/mo4omp3

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í?

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?

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í?

Ř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?

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?

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

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

}

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?

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

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 + ")"); } }

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.

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

Sestavení závislostí pomocí containeru

Application

DI container

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

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

ss)

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

Ú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?

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.

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.

Zvládli jsme to!

top related