Dependency injection Předávání závislostí Petr Kalivoda
Dependency injection – úvod Metoda, sloužící k odtržení tříd od jejich závislostí. Problém Výběr vhodné metody Příklady: Auto Letadlo Messaging Jak na to? Constructor injection Setter injection Interface injection
Bez Dependency injection Původ řidiče? Výměna? Servis? class Auto { private IŘidič řidič; public Auto() { řidič = new PostaršíŘidič("Franta Novák"); } public void nabourejDo(Objekt o) { řidič.setPudSebezáchovy(false); řidič.rozjeď(this); řidič.nastavKolizníKurz(this, o); }
Constructor injection Předání závislostí přes konstruktor Řidič se nenarodil v autě Můžu otestovat auto …ale? class Auto { private IŘidič řidič; public Auto(IŘidič řidič) { this.řidič = řidič; } public void nabourejDo(Objekt o) { řidič.setPudSebezáchovy(false); řidič.rozjeď(this); řidič.nastavKolizníKurz(this, o); } class ServiceFactory { private IŘidič řidič; public ServiceFactory() { this.řidič = new Řidička("Marcela"); } public IŘidič getŘidič() { return řidič; }
Constructor injection – problémy Závislost nemusím vždy potřebovat Střídání řidičů za jízdy? Přehlednost Auto a = new Auto(new ZkušenýŘidič(factory.getŘidič()); Stack náklad = a.getNáklad(); //k čemu mám řidiče? class Boeing747 { public Boeing747( IKapitán kapitán, IPilot druhý_pilot, ITechnik palubní_technik, Stack letušky Stack úklidová_četa, IDoktor doktor, … WTF ) { … }
Setter injection Můžu střídat řidiče Můžu testovat …ale? class Auto { private IŘidič řidič; public void setŘidič(IŘidič řidič) { this.řidič = řidič; }
Setter injection - problémy Objekt nemusí mít bez závislosti smysl Závislost nemusím chtít měnit za běhu Použití: class PersonalMessageHandler { private IMessageSender sender; public PersonalMessageHandler(IMessageSender sender) { this.sender = sender; } public void send(Message message, Person recipient) { sender.send(message, recipient); } handler = new PersonalMessageHandler(container.getSMTPMailSender()); handler.send(…);
Interface injection Vkládám závislosti na základě rozhraní Kontejner..ale? Spousta inject metod! interface IŘidičInjectable { public void injectŘidič(IŘidič řidič); } class Auto implements IŘidičInjectable {... } class NaiveIIDIContainer { public Řidič getŘidič() { return new Řidič("Guhlász Magyargaydok"); } public Object newInstance(Class clazz) { Object o = clazz.newInstance(); if(o instanceof IŘidičInjectable) { ((IŘidičInjectable)o).injectŘidič(getŘidič()); } return o; }
Interface injection bez interface PHP <?php class Foo { private $s; public function injectSomething(stdClass $s) { $this->s = $s; } class NaiveInjector { public function performInjections($object) { $re = new ReflectionClass($object); //reflexe foreach($re->getMethods() as $m) { //procházim parametry if(preg_match('#^inject[A-Z]#', $m->getName())) { foreach($m->getParameters() as $p) { //procházim typy $class = $p->getClass(); if( $class instanceof ReflectionClass && $class->getName() == 'stdClass‘ ) { //našel jsem $object->injectSomething(new stdClass); } }}}}} $f = new Foo(); (new NaiveInjector())->performInjections($f); //hotovo
Service Locator Statický registr služeb Netransparentní Testování – je náklad stále závislý na řidičovi? class ServiceLocator { private static HashMap services = new HashMap<>(); public static void add(String name, Object service) { services.put(name, service); } public static Object getService(String name) { return services.get(name); } class Auto { private IŘidič řidič = (IŘidič)ServiceLocator.getService("řidič");... }
Děkuji za pozornost. Otázky?