Vkládání závislostí

Vkládání závislostí (anglicky Dependency injection (DI)) je v objektově orientovaném programování technika pro vkládání závislostí mezi jednotlivými komponentami programu tak, aby jedna komponenta mohla používat druhou, aniž by na ni měla v době sestavování programu referenci. Dependency injection lze chápat jako novější název pro Inversion of Control (IoC), ale v užším významu.[zdroj?] Jedná se o konkrétní techniku IoC.

Účel

Pokud chce náš objekt používat služby jiného objektu (dále v textu jako komponenta) bez použití DI, pak zodpovídá za celý svůj životní cyklus, tedy inicializaci apod. Při aplikaci DI je ale náš objekt odstíněn od této správy, tu totiž zařizuje poskytovatel závislostí (anglicky dependency provider) neboli kontejner. Náš objekt tedy potřebuje už jen referenci na poskytovatele závislostí, který mu je schopen dodat hned několik různých komponent splňujících očekávání našeho objektu. Každá z těchto komponent může našemu objektu poskytovat rozdílné služby a v tom spočívá síla DI.

DI zahrnuje nejméně tři objekty, které spolu musí spolupracovat. Konzument, tedy objekt požadující služby. Poskytovatele těchto služeb mu dodá DI provider, který ve skutečnosti zodpovídá za celý životní cyklus poskytovatele. Provider neboli injector může být implementován několika způsoby, např. jako lokátor služeb, abstraktní továrna, tovární metoda, nebo pomocí nějakého z řady z frameworků, například Spring.

Martin Fowler poukazuje na tři různé vzory[1], jak lze objektu přidat externí referenci jiného objektu.

  1. Vkládání rozhraním – externí modul, který je do objektu přidán, implementuje rozhraní, jež objekt očekává v době sestavení programu.
  2. Vkládání setter metodou – objekt má setter metodu, pomocí níž lze závislost injektovat.
  3. Injekce konstruktorem – závislost je do objektu injektována v parametru konstruktoru již při jeho zrodu.

Implementace v jazyce Java

Příklad jednoduché injektáže si ukážeme na následujícím příkladě. Představte si člověka (konzumenta), který se chce stát florbalistou. K tomu, aby se jím mohl stát, potřebuje florbalovou hůl (požadovaná závislost). Obyčejný člověk si hůl neumí sám od sebe vyrobit. Programátor mu ji musí dát do ruky. Řekněme, že se hůl vyrábí v továrně na hokejky. Člověk tedy nepotřebuje znát postup, ani umět si hůl vyrobit. Prostě si zajde k výrobci hokejek, nebo si ji dokonce objedná a výrobce mu ji dopraví až do rukou. Výrobce je schopen poskytnout několik odlišných druhů hokejek s rozdílnými vlastnostmi.

Ukázka rozhraní, které budou jednotlivé komponenty implementovat.

public interface IHul{
	public void vystrelHoli();

	public void nahrejHoli();
}

public interface IClovek{

	public void vystrel();

	public void nahrej();
}

Těsná závislost bez použití dependency injection

public class Hul implements IHul{

	public void vystrelHoli(){
		...
	}

	public void nahrejHoli(){
		...
	}
}

public class Clovek implements IClovek{
	private IHul hul = new Hul();

	public void vystrel(){
		hul.vystrelHoli();
	}

	public void nahrej(){
		hul.nahrejHoli();
	}
}

public class Aplikace{
	public static void main(String[] args){
		IClovek cl = new Clovek();
		cl.vystrel();
		cl.nahrej();
	}
}

V tomto případě jsou všichni lidé od svého narození svázáni s konkrétní implementací hole. Existuje mezi nimi těsná závislost již v době překladu.

Manuálně vložená (injektovaná) závislost

public class Clovek implements IClovek{
	private IHul hul;

	public Clovek(IHul hul){
		this.hul = hul;
	}

	public void vystrel(){
		hul.vystrelHoli();
	}

	public void nahrej(){
		hul.nahrejHoli();
	}
}

public class ClovekFaktory{
	public static IClovek vytvorCloveka(){
		return new Clovek(new Hul());
	}
}

public class Aplikace{
	public static void main(String[] args){
		IClovek cl = ClovekFaktory.vytvorCloveka();
		cl.vystrel();
		cl.nahrej();
	}
}

Toto řešení sice přesunulo otázku závislosti z Člověka na továrnu, v tomto případě na celou aplikaci, míra závislosti je však stále velká - již při překladu programu musí být známa konkrétní implementace hole.

Závislost řízená frameworkem

Existuje několik různých frameworků, které jsou schopny řídit závislosti mezi komponentami. Vývojář si s jejich pomocí složí svou aplikaci z různých implementací komponent. O injektáž závislostí se v tomto případě stará kontejner, který si závislosti přečte z konfiguračních souborů, ve většině případů se pro tyto účely používá formát XML.

<servis-point id="VytvorFlorbalistu">
	<invoke-factory>
		<construct class="IClovek">
		<servis>Clovek</servis>
		<servis>Hul</servis>
		</construct>
	</invoke-factory>
</servis-point>

public class Aplikace{
	public static void main(String[] args){
		Service service = (Service)DependencyManager.get("VytvorFlorbalistu");
		IClovek cl = (IClovek)service.getServis(IClovek.class);
		cl.vystrel();
		cl.nahrej();
	}
}

Zde již vidíme uvolněnou závislost. Žádná z komponent není v době překladu programu závislá na druhé. Při tvorbě nového florbalisty se využije služba „VytvorFlorbalistu“, kontejner frameworku se podívá do XML souboru, aby zjistil které konkrétní implementace Člověka a Hole má zvolit a sestaví mezi nimi závislost. Implementace lze měnit bez zásahu do kódu aplikace, stačí upravit konfigurační soubor.

Existuje mnoho variant jak přidat objektu závislost na druhý objekt. Záleží na vývojáři, který způsob vyhodnotí jako nejlepší pro svou aplikaci.

Výhody

  • Provider může poskytovat řadu komponent k použití bez zásahu do kódu programu.
  • O přetypovávání se stará IoC kontejner.
  • Závislosti komponent jsou definovány explicitně, tedy jednodušší orientace v závislostech.
  • IoC kontejner lze ve většině případů konfigurovat mimo kód, jednotlivé komponenty je možné využít v jiných programech bez přepisování kódu.

Nevýhody

  • Menší přehlednost kódu.
  • Náročnější správa kódu.

Seznam DI frameworků

Embedded frameworky

  • PicoContainer
  • Google Guice

Aplikační frameworky

Standardní

Literatura

Prasanna, R.D.2009. Dependency Injection. Manning Publications Co. 2009. ISBN 978-1-933988-55-9.

Reference

Související články

Externí odkazy

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.