Dependency Injection
Total Page:16
File Type:pdf, Size:1020Kb
DEPENDENCY INJECTION DEPENDENCY INJECTION INGEGNERIA DEL SOFTWARE Università degli Studi di Padova Dipartimento di Matematica Corso di Laurea in Informatica, A.A. 2014 – 2015 Architetturali [email protected] Dependency injection, Model view controller Ingegneria del software mod. A Riccardo Cardin 2 INTRODUZIONE E CONTESTO PROBLEMA MovieLister nasconde le Scopo Esempio naive proprie dipendenze in un metodo. Separazione del comportamento di una componente dalla risoluzione delle sue dipendenze Motivazione Collegare due componenti in modo esplicito ne aumenta l’accoppiamento Progettazione unit‐test difficoltosa Riutilizzo scarso della componente Scarsa manutenibilità Le dipendenze vanno minimizzate!!! Ingegneria del software mod. A Riccardo Cardin 3 Ingegneria del software mod. A Riccardo Cardin 4 PROBLEMA STRUTTURA Utilizzo di classi factory Inversion of Control Utilizza metodi statici nel recupero di istanze concrete Il ciclo di vita degli oggetti è gestito da una entità ad interfacce esterna (container) Si può fare di meglio... Tutti i framework moderni implementano IoC Dependency Injection con IoC Le dipendenze sono “iniettate” dal container La componente dichiara solo le sue dipendenze Minimizzazione del livello di accoppiamento Diversi tipi di injection Constructor injection Setter injection Ingegneria del software mod. A Riccardo Cardin 5 Ingegneria del software mod. A Riccardo Cardin 6 STRUTTURA SOLUZIONE Dependency Injection con IoC Constructor injection Assembler risolve le dipendenze delle componenti Dipendenze dichiarate come parametri del costruttore Il ciclo di vita degli oggetti è deciso dal container public class MovieLister { private MovieFinder finder; Configurazione: meta‐linguaggio (XML) o programmatica public MovieLister(MovieFinder finder) { // Dichiarazioe dip. this.finder = finder; Cambio di movie finder Cambio di configurazione } // ... } Vantaggi Permette di costruire oggetti validi sin dalla loro istanziazione Favorisce la costruzione di oggetti immutabili Svantaggi Telescoping A volte è difficile comprendere il significato dei parametri Ingegneria del software mod. A Riccardo Cardin 7 Ingegneria del software mod. A Riccardo Cardin 8 SOLUZIONE GOOGLE GUICE Setter injection Lightweight DI framework Dipendenze dichiarate come metodi setter Class injection (@Inject – JSR‐330) public class MovieLister { Configurazione Java estendendo AbstractModule private MovieFinder finder; public void setFinder(MovieFinder finder) { public class MovieModule extends AbstractModule { this.finder = finder; @Override } // ... protected void configure() { } // Istruisce il container di come risolvere la dipendenza bind(MovieFinder.class).to(ColonMovieFinder.class); } Vantaggi } Individuazione precisa delle dipendenze e dei loro nomi public class MovieLister { Lavora meglio con le gerarchie di classi // L’annotazione istruisce il container di risolvere // automaticamente le dipendenze dichiarate Svantaggi @Inject public MovieLister(MovieFinder finder) { La componente è costruita per passi this.finder = finder; } // ... Non è abilitante all’immutabilità } Ingegneria del software mod. A Riccardo Cardin 9 Ingegneria del software mod. A Riccardo Cardin 10 GOOGLE GUICE GOOGLE GUICE Lightweight DI framework Lightweight DI framework Method (setter) injection Cointainer è una struttura Map<Class<?>, Object> public class MovieLister { // L’annotazione istruisce il container di risolvere Non è possibile avere due oggetti dello stesso tipo // automaticamente le dipendenze dichiarate È possibile utilizzare qualificatori ulteriori per questo caso @Inject public setFinder(MovieFinder finder) { Si integra con AOP, Servlet spec., DAO, ... this.finder = finder; } // ... @Named, @Singleton, @SessionScoperd, @RequestScoped... } public static void main(String[] args) { Field injection // Guice.createInjector() takes your Modules, and returns a new // Injector instance. Most applications will call this method public class MovieLister { // exactly once, in their main() method. // Risolta automaticamente dall’injector. Piu’ conciso ma Injector injector = Guice.createInjector(new MovieModule()); // meno verificabile @Inject MovieFinder finder; // Now that we've got the injector, we can build objects. } MovieLister lister = injector.getInstance(MovieLister.class); } Ingegneria del software mod. A Riccardo Cardin 11 Ingegneria del software mod. A Riccardo Cardin 12 SPRING SPRING “Spring is a «lightweight» inversion of control and aspect oriented Configurazione XML container framework” org.springframework.beans.factory.BeanFactory Lightweight Implementazione del pattern factory, costruisce e risolve le Non è intrusivo, gli oggetti sviluppati non dipendono da dipendenze classi del framework Framework/Container org.springframework.context.ApplicationContext La configurazione utilizza XML, o annotazioni, o Java Costruita sulla bean factory, fornisce ulteriori funzionalità Lo sviluppatore può concentrarsi sulla logica di business AOP, transazionalità, ... Cointainer è una struttura Map<String, Object> ApplicationContext ctx = Utilizza semplici POJO: Bean new ClassPathXmlApplicationContext( Supporta sia constructor, che setter injection "com/springinaction/springidol/filename.xml"); // ... JEE replacement MVC, Front controller, DI, AOP, JDBC Template, Security ... MovieLister ml = (MovieLister) ctx.getBean("movieLister"); Ingegneria del software mod. A Riccardo Cardin 13 Ingegneria del software mod. A Riccardo Cardin 14 SPRING SPRING Configurazione XML Configurazione XML Dependency injection attraverso proprietà Dependency injection attraverso costruttori Spring risolve automaticamente la scelta del costruttore Utilizzo metodi setter e getter <?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> <bean id="movieLister" class=“MovieLister"> <beans> <constructor-arg ref="movieFinder"/> <bean id="movieLister" class=“MovieLister"> </bean > <!-- La classe ha come proprieta’ finder... --> <bean id=“movieFinder" class="ColonMovieFinder"> <property name="finder" ref="movieFinder" /> <constructor-arg value=“movies.csv"/> </bean> </bean> <bean id=“movieFinder" class="ColonMovieFinder"> </beans> <property name="file" value="movies.csv“ /> </bean> </beans> Oppure factory methods, init,destroy methods... Ingegneria del software mod. A Riccardo Cardin 15 Ingegneria del software mod. A Riccardo Cardin 16 SPRING SPRING Configurazione Java Wiring utilizzando annotazioni @Configuration: dichiara una classe configurazione Permette una gestione migliore della configurazione @Bean: dichiara un bean in progetti grandi @Configuration Introduce una dipendenza da framework esterni public class MovieConfig { @Bean Constructor injection @Autowired public MovieLister lister(){ @Inject, annotazione JSR‐330 return new MovieLister( finder() ); , annotazione JSR‐250 } @Resource bean id <?xml version="1.0" encoding="UTF-8"?> @Bean <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" public MovieFinder finder(){ "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> return new ColonMovieFinder("movies.csv"); </beans> } <context:annotation-config/> } <context:component-scan base-package="org.example"/> ApplicationContext ctx = [...] new AnnotationConfigApplicationContext(MovieConfig .class); Ingegneria del software mod. A Riccardo Cardin 17 Ingegneria del software mod. A Riccardo Cardin 18 SPRING JAVASCRIPT Wiring utilizzando annotazioni Dependency injection in Javascript @Inject/@Autowired Container è una mappa [string, function] Ricerca per tipo il bean della proprietà e lo usa come id Linguaggio non tipizzato staticamente Si utilizza su costruttori, proprietà, ... Non ha interfacce esplicite Il bean non deve essere ambiguo Disambiguazione tramite @Named per l’ID @Inject JS è strutturato a moduli (module pattern) private Instrument instrument; Injection di oggetti o interi moduli @Inject @Named("guitar") // Fornisce nome differente dal tipo Esistono diverse librerie (API) per la DI private Instrument instrument2; RequireJS/AMD ‐ http://requirejs.org/ Autodiscovery Inject.js ‐ http://www.injectjs.com/ @Component, @Controller, @Service, ... AngularJS (framework) ‐ https://angularjs.org/ Ingegneria del software mod. A Riccardo Cardin 19 Ingegneria del software mod. A Riccardo Cardin 20 ANGULARJS ANGULARJS Javascript framework Dependency Injection Client‐side $provide: risolve le dipendenze fra le componenti Model‐View‐Whatever Viene invocato direttamente da Angular al bootstrap // Provide the wiring information in a module Ritorna il servizio MVC per alcuni aspetti (controller)… angular.module('myModule', []). $provide …MVVM per altri (two‐way data binding) // Teach the injector how to build a 'greeter' // Notice that greeter itself is dependent on '$window' factory('greeter', function($window) { // This is a factory function, and is responsible for Utilizza HTML come linguaggio di templating // creating the 'greet' service. Non richiede operazioni di DOM refresh return { greet: function(text) { Controlla attivamente le azioni utente, eventi del browser $window.alert(text); "Ricetta" di come } }; costruire greeter Dependence injection }); Fornisce ottimi strumenti di test // Request any dependency from the $injector