DEPENDENCY INJECTION INGEGNERIA DEL SOFTWARE Università degli Studi di Padova Dipartimento di Matematica Corso di Laurea in Informatica Architetturali [email protected] Dependency injection, Model view controller

Ingegneria del software 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 Riccardo Cardin 3 Ingegneria del software Riccardo Cardin 4 PROBLEMA STRUTTURA

¢ Utilizzo di classi factory ¢ — 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 Riccardo Cardin 5 Ingegneria del software 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 Riccardo Cardin 7 Ingegneria del software Riccardo Cardin 8 SOLUZIONE GUICE

¢ Setter injection ¢ Lightweight DI framework — Dipendenze dichiarate come metodi setter — Class injection (@Inject – JSR-330) public class MovieLister { — Configurazione 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 su 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 Riccardo Cardin 9 Ingegneria del software Riccardo Cardin 10

GOOGLE GUICE GOOGLE GUICE

¢ Lightweight DI framework ¢ Lightweight DI framework — Method (setter) injection — Cointainer è una struttura Map, Object> public class MovieLister { — // L’annotazione istruisce il container su come 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... } ¢ https://github.com/google/guice/wiki/BindingAnnotations

— Field injection public static void main(String[] args) { public class MovieLister { // Guice.createInjector() takes your Modules, and returns a new // Risolta automaticamente dall’injector. Piu’ conciso ma // Injector instance. Most applications will call this method // meno verificabile // exactly once, in their main() method. @Inject MovieFinder finder; Injector injector = Guice.createInjector(new MovieModule()); } // Now that we've got the injector, we can build objects. MovieLister lister = injector.getInstance(MovieLister.class); }

Ingegneria del software Riccardo Cardin 11 Ingegneria del software 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 ApplicationContext ctx = ¢ Utilizza semplici POJO: Bean new ClassPathXmlApplicationContext( — Supporta sia constructor, che setter injection "com/springinaction/springidol/filename.xml"); ¢ JEE replacement // ... — MVC, , DI, AOP, JDBC Template, Security ... MovieLister ml = (MovieLister) ctx.getBean("movieLister");

Ingegneria del software Riccardo Cardin 13 Ingegneria del software 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 "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> @Bean return new ColonMovieFinder("movies.csv"); } } ApplicationContext ctx = [...] new AnnotationConfigApplicationContext(MovieConfig.class); Ingegneria del software Riccardo Cardin 17 Ingegneria del software 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 Riccardo Cardin 19 Ingegneria del software Riccardo Cardin 20 ANGULARJS 1.6 ANGULARJS 1.6

¢ Javascript framework ¢ Dependency Injection — Client-side — $provide: risolve le dipendenze fra le componenti — Model-View-Whatever ¢ Viene invocato direttamente da 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 angular.injector(['myModule', 'ng']).get('greeter');

Ingegneria del software Riccardo Cardin 21 Ingegneria del software Riccardo Cardin 22

ANGULARJS 1.6 ANGULARJS 1.6

¢ Dependency Injection ¢ Dependency Injection — Factory methods: costruiscono le componenti ¢ Utilizzano recipe (ricette) angular.module('myModule', []). config(['depProvider', function(depProvider){ //... }]). factory('serviceId', ['depService', function(depService) { //... }]). directive('directiveName', ['depService', function(depService) { //... }]). filter('filterName', ['depService', function(depService) { //... }]). run(['depService', function(depService) { //... }]);

Ingegneria del software Riccardo Cardin 23 Ingegneria del software Riccardo Cardin 24 SCALA SCALA

// Declares a repository ¢ trait UserRepositoryComponent { Cake Pattern val userRepository: UserRepository — class UserRepository { Utilizzo di una notazione dedicata (self-type def findAll() = Array[User]() // fake implementation annotation) e dei trait per dichiarazione delle def save(user: User) = "Saving a user..." // fake implementation } dipendenze e loro risoluzione } // Declares a service that needs a repository trait FooAble { trait UserServiceComponent { this: UserRepositoryComponent => def foo() = "I am a foo!" val userService: UserService } class UserService { class BarAble { this: FooAble => // self-type annotation def findAll() = userRepository.findAll def bar = "I am a bar and " + foo() def save(user: User) = userRepository.save(user) } } val barWithFoo = new BarAble with FooAble // mixin } // Configuration object that binds dependencies object ComponentRegistry extends — Utilizzo di contenitori dedicati per risolvere le UserServiceComponent with UserRepositoryComponent { // Dependency injection dipendenze val userRepository = new UserRepository ¢ Divisione dei concetti di business dai dettagli tecnici val userService = new UserService }

Ingegneria del software Riccardo Cardin 25 Ingegneria del software Riccardo Cardin 26

CONCLUSIONI RIFERIMENTI

Dependency injection means giving an object its own ¢ , Elements of Reusable Object Oriented Software, instance variables. Really. That’s it. GoF, 1995, Addison-Wesley James Shore ¢ Inversion of Control Containers and the Dependency Injection pattern http://martinfowler.com/articles/injection.html ¢ Vantaggi ¢ Google Guice – Motivation — Migliora la fase di testing https://github.com/google/guice/wiki/Motivation ¢ Isolamento delle componenti à Maggior riuso ¢ Spring vs Guice: The one critical difference that matters http://gekkio.fi/blog/2011-11-29-spring-vs-guice-the-one-critical- — Migliora la resilienza del codice difference-that-matters.html ¢ Manutenzione e correzioni componenti specifiche ¢ Spring – The IoC Container — Migliora la flessibilità http://docs.spring.io/spring/docs/current/spring-framework- ¢ La disponibilità di più componenti simili permette di scegliere reference/html/beans.html a runtime la migliore

Ingegneria del software Riccardo Cardin 27 Ingegneria del software Riccardo Cardin 28 RIFERIMENTI GITHUB REPOSITORY

¢ Angular Dependency Injection https://docs.angularjs.org/guide/di ¢ JavaScript Dependency Injection http://merrickchristensen.com/articles/javascript-dependency- injection.html ¢ Eat that cake! http://rcardin.github.io/design/2014/08/28/eat-that- cake.html ¢ Resolving your problems with Dependency Injection http://rcardin.github.io/programming/software- https://github.com/rcardin/swe design/java/scala/di/2016/08/01/resolve-problems-dependency- injection.html

Ingegneria del software Riccardo Cardin 29 Ingegneria del software Riccardo Cardin 30