Dependency Injection ve 2.1: sloučení factories a services
- David Grudl
- Nette Core | 8250
(Navazuji na starší příspěvek)
V současnosti lze definovat v DIC dva typy entit: služby a továrničky.
Rozdíl je v tom, jestli se instance služby uchovává a je dostupná přes
metodu getService
, nebo se pokaždé vytvoří nová při volání
metody create...
. Továrničky tak mohou mít navíc i parametry.
A compiler umí také vytvářet implementace továrniček definovaných
rozhraním.
Uvažuji nad tím, že bych rozdíl mezi obojím zrušil. Vše by se
definovalo v jedné sekci services
, takže nebude potřeba
přemýšlet nad tím, jestli jde o službu nebo továrnu. Rozdíl by
spočíval pouze na uživateli, jestli by k entitě přistupoval přes
getService()
nebo createService()
.
Narazil jsem na jediný problém, a to je nejasnost v konfiguraci při odkazování se na jinou službu:
Pokud se služba @a
nacházela v sekci factories
,
znamenal odkaz @a
zavolání této továrny a do konstruktoru
OtherClass
se předala nově vytvořená instance
MyClass
.
Pokud sekce sloučíme, @a
bude znamenat klasický odkaz na
sdílenou instanci služby a tedy i BC break. Způsob, jak docílit vytvoření
nové instance, je
krkolomnější: @container::createService(a)
- Filip Procházka
- Moderator | 4668
Moc to nechápu… Bavíme se zde pouze o sloučení sekcí? „implement“ by fungovalo dál?
Btw, již teď používám
Napadá mě tedy, pokud chci předat novou instanci služby (pokud by se sloučily ty sekce), tak by se to dalo napsat takto
Ale @container::createA()
bych asi taky přežil :)
- David Grudl
- Nette Core | 8250
Honza Marek napsal(a):
To mi zní jako zrušení factories bez náhrady. Jsem pro.
Factories se pochopitelně zachová, přesněji rozšíří ;)
Filip Procházka napsal(a):
Napadá mě tedy, pokud chci předat novou instanci služby (pokud by se sloučily ty sekce), tak by se to dalo napsat takto
Jde skutečně jen o sloučení sekcí.
Pokud má služba @a
parametry, pochopitelně by se volala jako
továrna. Problém je, pokud parametry nemá. Pak je při současné
implementaci velmi komplikované rozlišit mezi @a
a
@a()
.
- Šaman
- Člen | 2667
Jak tohle teď vypadá?
Oproti 2.10 mi v @dev nefunguje
$container->createFoo();
, pokud mám foo
v sekci
factories
.
Našel jsem tohle vlákno, přesunul továrny do sekce services
a začal je vytvářet pomocí $container->createService('foo')
a to mi zase nefunguje, protože všechny komponenty potřebují v konstruktoru
nějaký kontejner a ono se jim to snaží vnutit nějaký z configu. A těch
je tam spousta.
Nakonec jsem nevím proč zkusil přesunout definici továren zpět do sekce
factories
a vytvářet je pomocí createService()
a
vypadá to, že to funguje.. ale je to dost WTF. Je to už finální stav, nebo
se to ještě bude měnit?
- Filip Procházka
- Moderator | 4668
Pokud někde vytváříš potomky
Nette\ComponentModel\Component
, tak bych důrazně doporučoval
překrýt konstruktor, aby nesomroval ty defaultní parametry (parent
a name).
- Šaman
- Člen | 2667
No, komponenty mám v configu a v továrničce je sosám pomocí
$container->createService($name)
. Co myslíš tím překrýt
konstruktor? Vždyť v konstruktoru komponenty přece nemám k dispozici
parenta, ne? (pokud si ho nenechám předat parametrem). A $name vlastně
taky ne.
Editoval Šaman (4. 6. 2013 5:04)
- Honza Marek
- Člen | 1664
Nutí někdo autowiring, aby cpal služby i do nepovinných parametrů? Podle mě by to neměl dělat.
- Filip Procházka
- Moderator | 4668
vojtech.dobes napsal(a):
Ústupek autowiringu, tak říkajíc.
Především plus pro api třídy. V konstruktoru tohle imho stejně nemá co dělat. Ale to už jsme OT :)
- Šaman
- Člen | 2667
Filip Procházka napsal(a):
Myslím tím prosté
Díky, tohle v BaseControlu řeší problém.
Chápu to tedy tak, že i když sekce factories
asi z důvodu
zpětné kompatibility funguje postaru, tak doporučované je mít všechno v
services
a služby od továren rozlišovat až při použití –
getService() vs. createService()?