Date post: | 14-Feb-2017 |
Category: |
Documents |
Upload: | jiri-matula |
View: | 12 times |
Download: | 0 times |
Dependency injectionJiří Matula
Neruším? Ráda bych vám pomohla s Vaší závislostí na ostatních!
Obsah
1.Co je to Dependency Injection (DI) 2.Motivace proč se zabývat DI3.Typy DI4.Problémy5.DI Container6.Závěr - testík
Dependency injection (DI)
• Návrhový vzor z rodiny IoC (Inversion of Control).• Problém : Skryté závislosti třídy (skryté = těžce
kontrolovatelné).• Řešení: zřejmé předávání závislostí = odebrání třídám
zodpovědnosti za získávání objektů, které potřebují ke své činnosti.• Uplatňuje se princip popisu závislostí pomocí API třídy. • Lze si jej představit pod mottem - “Když něco chceš, tak si o
to řekni!”
Vizualizace závislostí
(Satisfied person)
(Water)
(Alcohol)
(Friends)
(Vegetable)(Meat)
(Cheese)
Proč se obtěžovat s DI?
Zvolnění vazeb mezi objekty,jednodušší testovatelnost,nutí programátora řešit vazby mezi objekty = čistější přehlednější kód,pomáhá dodržovat správný objektový návrh,pravdivé API tříd.
Junior programmer Garry – “Whatever, I love my spaghetti !”
Constructor Injection• Hlášení závislosti přímo v konstruktoru třídy.• Problémy: • Lazy loading (vytváření objektů v momentě, kdy jsou opravdu
potřeba), • Constructor hell (příliš mnoho závislostí v konstruktoru třídy).
public void Company() { this.worker = new Worker(); this.slacker = new Slacker();
}
// constructor injectionpublic void Company(Worker worker, Slacker slacker) {
this.worker = worker; this.slacker = slacker;
}
Setter Injection
• Hlášení závislostí přímo při volání setter funkce. • Lze dobře uplatnit pro inicializaci objektu mimo konstruktor
třídy.@Injectpublic void setHelper(Helper helper) {
this.helper = helper; }
Property injection• Je velmi podobné constructor injection. K hlášení závislostí se
používá anotací přímo u deklarace proměnné. Výhodou je stručnost.• Nutností je DI container, který bude umět s touto anotací
pracovat a nastavit odkazující proměnnou na již inicializovaný objekt.
public class ClientsController {
// Property injection@Inject private final UserDAO
userDAO;
public ClientsController() {
} }
public class ClientsController {
private UserDAO userDAO;
public ClientsController(UserDAO userDao) { this.userDao = userDao;
// constructor injection}
}
Interface Injection• Nehlásíme závislost na konkrétní třídu, hlásíme závislost pouze na interface,• jedná se o velmi silný nástroj – zvyšuje úroveň abstrakce v
kódu.
public void setHelper(Employee helper) { this.helper = helper;
}
public Company(Employee worker, Employee slacker) { this.worker = worker; this.slacker = slacker;
}
interface Employee { public void work();
public void pretendWorking(); }
Spaghetti code, je v souladu s DI?public class Company{
protected Worker worker;
protected Slacker slacker;
public Companz() { this.worker = new Worker();this.slacker = new Slacker();
}
public void open(){this.worker.work(); this.slacker.pretendWorking();
customer = new Customer(); System.out.println(“<h1> Welcome! How can I help you?</h1>”);this.worker.serverCustomer();System.out.println(“<p>” + customer.wish + ”</p>”);
} }
Senior programmer John - “Garry, you are fired!”
Problémy - Constructor hell
public function Controller(IHttpRequest request, IHttpResponse response,User user, UserModel userModel, Language
language, DataSource dataSource, ....) {
// rest of the code}
• Přílišné množství parametrů již přímo v konstruktoru třídy,• odhaluje tak nesprávné rozvržení tříd,• řešit lze za pomocí refaktoringu tříd.
Jesus Christ, so many dependencies!!
Problémy - DI vs. Lazy loading• Lazy loading – návrhový vzor, kdy se vytváření instance
objektu se odkladá do doby než je opravdu potřeba,• z důvodu optimilizace je přínosné tento návrhový vzor
používat,• naopak DI požaduje pro své třídy již vytvořené instance
(závislosti).
Junior Garry – No way, they troll me all the time!
Service Locator – zlé dvojče DI
• Jedná se také o návrhový vzor, nicméně jde proti smyslu DI (antipattern)• Třída se totiž nehlásí k jednotlivým závislostem. Všechny
závislosti získává skrze globální objekt (service locator).• Nicméně lze přejít pak jednoduše k DI.public class ClientsController {
private final UserDAO userDAO;
public ClientsController(ServiceContainer $services) { this.userDao = (UserDao)$services-
>getService("UserDAO"); }
}Hell yeah, your classes are liars again!
DI Container (DIC)
• Příliš mnoho závislostí (závislé třídy) => potřebujeme je spravovat, k těmto účelům slouží právě DI kontejner,• DI kontejner dává již připravené instance tříd vždy jeho
žadateli,• pravidlem je, že o existencí DI kontejneru by mělo vědet
minimální množství kódu,• příklad: Google Guice Cointainer (není jediný).
Pohled na aplikaci jako stavbu tříd
Application
Database
Connection
DaoServices
Resources
DataSource
GUI
Other Clasess…
Na co teda DI container? • Pokud svou aplikaci popíšete jako strom závislostí. Není nic
jednoduššího než si ji nechat sestavit právě DI Containerem.• Ten drží konfiguraci tříd celé aplikace, nahrazuje pokoutné
Environment objekty.
Hey container, gimme the Application!
Yess, sir!
Konfigurace DI containeru• Slouží k správné inicializaci prostředí aplikace, resp. jejich tříd. To,
jakým způsobem se konfigurace provádí, záleží na konkrétní implementaci containeru (anotace, třídní objekt, xml soubor...)import com.google.inject.Binder; import com.google.inject.Module; import com.google.inject.Scopes;
public class DependencyConfig implements Module { @Override public void configure(Binder binder) {
binder.bind(Storage.class).to(DatabaseStorage.class).in(Scopes.SINGLETON);}
//example of Google Guice Container configuration}
DIC a persistence objektů • DI kontejnery nám umožňují řídit životnost objektů =>
obrovský potenciál DI• Problém návrhového vzoru Singleton:• Nikdy nemůžeme dopředu vědět zda třída bude opravdu Singletonem
či nikoli. • Není přímou zodpovědností třídy se starat zda bude jedináčkem či
nikoli.• Za pomocí DI kontejneru se tyto problémy dají vyřešit.
DIC – není Singleton jako Singleton
@Singletonpublic class Company {
protected Worker worker;
protected Slacker slacker;
public Firma() { this.worker = new Worker();this.slacker = new Slacker();
}
}
public class Company { private static Company instance = null;
private Company() {}
public static Company getInstance() { if (instance == null) {
instance = new Singleton(); } return instance;
} }
Kontrolní otázky1.V čem je podstata návrhového vzoru Dependency injection
(DI)?2. Jaké výhody přináší DI?3. Jaké máme typy DI?4. Jaké problémy mohou nastat při aplikování vzoru DI?5.K čemu slouží Dependency Injection Container? 6.Dalo vám to něco?
Questions?