Vstříkni to tam - Reparát

Patrik Votoček

V Sobotu jsem na Poslední Sobotě měl s Filipem Procházkou přednášku Vstříkni to tam - průvodce světem Dependency Injection.

Už při přednášce jsme upozorňovali, že nám poněkud nevyšel plán a přednášku jsme “odfláknuli”. Jelikož mě to ale nedá spát, tak jsem se rozhodl že se základ pokusím vysvětlit prostřednictvím tohoto článku.

Pojďme se tedy podívat, co to Dependency Injection (česky “závislé vstřikování”) je.

Dependency Injection

Dependency Injection je návrhový vzor (technika Inversion of Control), který nám říká, jak trasparentně propojovat jednotlivé komponenty systému.

Jako příklad Dependency Injection si můžeme představit mobilní telefon a baterii. K tomu, aby mohlo mobil fungoval, bude potřebovat baterii. Pokud baterii nemá, prostě ho nezapnete.

class Battery implements IBattery {}

class OldNokia
{
	private $battery;

	public function __construct(IBattery $battery)
	{
		$this->battery = $battery;
	}

	public function turnOn()
	{
		$this->battery->use($this);
	}
}

Vytvoříme mobil a vložíme do něj baterii.

$battery = new Battery;
$mobile = new OldNokia($battery);

$mobile->turnOn();

Service Locator

Service Locator návrhový vzor, který nám umožňuje propojení komponent systému tzv. na vyžádání.

Pokud použijeme analogii s mobilem a baterii.

class iPhone
{
	protected function getBattery()
	{
		return Nette\Environment::getService('battery');
	}

	public function turnOn()
	{
		$this->getBattery()->use($this);
	}
}

Máme mobil, o kterém víme že má baterii ale nemáme možnost jeho baterii jakkoli ovlivnit nebo vyměnit. Představte si, že vám baterie odejde do křemíkového nebe. U staré Nokie ji prostě vyměníte za novou a fungujete dál. Kdežto s iPhonem musíte zajít do servisu, kde vám ji vymění servisák.

Představte si, že jdete se stervisákem opravujícím iPhony na pivo a on vám v nestřežené chvíli vymontuje baterii z vašeho iPhone. Vy se budete divit, proč vám nejde zapnout (v podstatě nemáte šanci přijít na to, že je to vymontovanou baterií - nebereme-li v potaz váhu). U staré Nokie sundáte zadní kryt a hned víte - aha baterie! Tak tam dáte jinou (nebo ji z toho šprýmaře vymlátíte).

Jediná výhoda Service Locatoru oproti Dependency Injection je lazy-loading. V analogii mobilního telefonu je to třeba WiFi. Zapnete jí až když jí potřebujete (problém bude, když až v tu chvíli zjistíte, že váš mobil vlastně WiFi nemá).

Typy Dependency Injection

Konstruktor

Používá se pro závislosti, bez kterých není objekt schopen řádného fungování. Například naše baterie v mobilu.

class SomeChineseMobilePhone
{
	private $battery;

	public function __construct(IBattery $battery)
	{
		$this->battery = $battery;
	}
}

$mobile = new Mobile($battery);

Setter

Používá se pro závislosti, bez kterých je objekt schopen fungovat. Například SIM karta v našem mobilu.

class SomeChineseMobilePhone
{
	private $sim;

	public function setSim(ISim $sim)
	{
		$this->sim = $sim;
	}
}

$mobile->setSim($sim);

Property

Používá se závislostí, bez kterých se objekt obejde zcela a není potřeba kontroly, o jaký prvek se jedná. Například uživatel (majitel) našeho mobilního telefonu (žena, muž, důchodce, dítě v konečném důsledku to může být i kočka).

class SomeChineseMobilePhone
{
	public $owner;
}

$mobile->owner = $radvis;

Dependency Injection != DI Container

Dependency Injection je způsob předávání závislostí. Aby se nám to dělalo lépe, je vhodné k tomu mít nástroj. Tím nástrojem je právě DI Container.

DI Container funguje tak, že si do něj zaregistrujete služby a ten je při vyžádání vytvoří a to včetně předání (nastavení) všech jejich závislostí. Tím nám vznikne graf závislostí, který udržujeme na jednom jediném místě.

Jak používat DI v Nette najdete v dokumentaci http://doc.nette.org/cs/configuring & http://doc.nette.org/cs/dependency-injection

«