Dependency Injection vs $this->context->getService()

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Kakaku
Člen | 27
+
0
-

Zdravím,
narazil jsem pro mě naprostou novinku a to $this->context->getService().

Napadá mě, že je zbytečné volat v konstruktoru presenteru služby:

class MyPresenter extends Presenter
{
	public function __construct(ArticleManager $articleManager)
	{
		$this->articleManager = $articleManager;
	}
}

Ale místo toho použít toto:

class MyPresenter extends Presenter
{
	public function __construct()
	{
		$this->articleManager = $this->context->getService('articleManager');
	}
}

Za předpokladu, že mám službu zaregstrovanou v config.neon:

services:
	articleManager: App\FrontModule\Model\ArticleManager

Funkční to je. Teď je otázka, zda-li je to z návrhového vzoru špatně (nikde se o tom nepíše) a pokud ano, tak proč?
Díky :)

Šaman
Člen | 2665
+
+6
-

Ano, je to špatný návrh a píše se o tom.
Tím, že používáš DI container sice mnoho typických problémů vyřešíš (např. když chceš třídě podstrčit testovací objekty), ale z hlediska návrhu: Tvoje třída MyPresenter vyžaduje pro svůj běh ArticleManager. Tak si o něj má říct. V druhém případě ale říká, že chce nějaký kontejner (ten se dokonce předává v Nette automaticky) a už se v něm pohrabe sama. Nikdo nezaručí, že tam ta třída ArticleManager je. A hlavně nikdo ani neví, že ho ten MyPresenter potřebuje, protože to vůbec není zřejmé z jeho veřejného rozhraní. Aby se tahle závislost objevila, je potřeba prohrabat přímo kód.

Editoval Šaman (8. 7. 2016 0:08)

CZechBoY
Člen | 3608
+
0
-

Ja DIC (di container) pouzivam jen kdyz chci nejakou tridu dynamickyho jmena – treba podle parametru v konstruktoru.

matopeto
Člen | 395
+
0
-

@CZechBoY to mi pride tiez take divne ak musis nieco take pouzivat. Je k tomu nejaky dobry Use Case?

CZechBoY
Člen | 3608
+
0
-

@matopeto mam treba urcitej typ zaznamu v db a kazdy typ se zobrazuje jinym zpusobem – jinde si vezme dodatecny data, zobrazi jiny text atd.
Tak je jednodussi mit 60 trid dynamicky vybiranych. Nanic jinyho jsem neprisel :-)

matopeto
Člen | 395
+
0
-

@CZechBoY neviem o to by sa mal starat view, mal by si mat list tych roznych objektov (napr nejaky spolocny predok, kvoli typovej kontrole), a vo view cez nejaky template selector podla typu vybrat spravnu sablonu na zobrazenie.

CZechBoY
Člen | 3608
+
+1
-

@matopeto tak jde o sablonu a jeste tridu ktera vi odkud vzit jaky data.
Neresil bych to uz tady ;-)

Lukes
Silver Partner | 68
+
0
-

Kakaku napsal(a):

Zdravím,
narazil jsem pro mě naprostou novinku a to $this->context->getService().
......

Osobně mi tvoje řešení přijde mnohokrát „ukecanější“ než ten předepsaný způsob, když pominu, že to jde proti best practise. Navíc musíš služby pojmenovávat, což je opruz. Osobně používám v presenterech anotace @inject (https://doc.nette.org/…dependencies), což je naprosto luxusní záležitost. Navíc ty presenter nevytváříš, tak proč to řešit, když ho sestavuje Grudl(teda DI Kontejner). To je právě ta krása a podstata DI. „Ať se o předání služeb postará někdo jiný/ten kdo vytváří objekt“ Proč to mám řešit já ;-)

Navíc přistupovat v aplikaci přímo do DIC ($this->context v presenteru) není z 99% vůbec nutné a jde to vždy řešit lépe.

Eda
Backer | 220
+
0
-

Deklarovat své závislosti ve veřejném rozhraní je to nejlepší, co můžeš udělat.

Doporučuju tedy se používání contextu vyhnout velkým obloukem. Je to skrytá závislost a navíc vyžaduješ mnohem víc, než reálně potřebuješ.

Už mnoho programátorů přepisovalo své projekty ze Service locatoru na DI, protože narazili na nějaký reálný problém ať už při refaktoringu, nebo třeba při testování. Pokud to začneš psát „správně“ rovnou, ušetříš si v budoucnu dost práce s přepisováním :-)

Felix
Nette Core | 1245
+
+3
-

Trochu vody do mlyna. V presenterech by jsi container/context skoro nemel pouzivat, stejne tak jako v komponentach. A v 95% vsech trid.

Nicmene je dulezity rict, ze service locator je jeden z principu a neda se rict, ze je spatny. Je vhodny, kdyz clovek vi jak ho pouzivat a kde ho pouzivat.