Dependency Injection vs $this->context->getService()
- Kakaku
- Člen | 27
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
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)
- Lukes
- Silver Partner | 68
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
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
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.