1 dependency injection sandro pedrazzini approfondimento dependency injection

Download 1 Dependency Injection Sandro Pedrazzini Approfondimento Dependency Injection

Post on 02-May-2015

212 views

Category:

Documents

0 download

Embed Size (px)

TRANSCRIPT

  • Slide 1
  • 1 Dependency Injection Sandro Pedrazzini Approfondimento Dependency Injection
  • Slide 2
  • 2 Dependency Injection Sandro Pedrazzini Dependency Injection (DI) Modalit di configurazione di un oggetto, in cui le dipendenze delloggetto vengono specificate da entit esterne Lalternativa che loggetto stesso si definisca da solo, al suo interno, le dipendenze Anche chiamata Inversion of Control (IoC), che per ha un significato pi esteso (principio del framework in generale)
  • Slide 3
  • 3 Dependency Injection Sandro Pedrazzini Esempio Classe che gestisce lesecuzione del pagamento di un certo ordine (BillingService) Sia la classe responsabile dellelaborazione dei dati della carta di credito (CreditCardProcessor), sia la classe responsabile di mantenere le informazioni di log (TransactionLog) del pagamento devono poter essere modificate
  • Slide 4
  • 4 Dependency Injection Sandro Pedrazzini Esempio (2)
  • Slide 5
  • 5 Dependency Injection Sandro Pedrazzini Esempio (2) BillingService carica lordine sulla carta di credito. La transazione verr registrata (log) sia in caso di riuscita, sia in caso di insuccesso public interface IBillingService { Receipt chargeOrder(Order order, CreditCard creditCard); }
  • Slide 6
  • 6 Dependency Injection Sandro Pedrazzini Esempio (3) Schema di elaborazione public Receipt chargeOrder(Order order, CreditCard creditCard) { ChargeResult result = processor.process(order.getAmount(), creditCard); transactionLog.logChargeResult(result); }
  • Slide 7
  • 7 Dependency Injection Sandro Pedrazzini Esempio (4) public class BillingService implements IBillingService { public Receipt chargeOrder(Order order, CreditCard creditCard) { ICreditCardProcessor processor = new PaypalCreditCardProcessor(); ITransactionLog transactionLog = new DatabaseTransactionLog(); try { ChargeResult result = processor. process(order.getAmount(), creditCard); transactionLog.logChargeResult(result); return... } catch (UnreachableException e) {... }
  • Slide 8
  • 8 Dependency Injection Sandro Pedrazzini Esempio (4) Situazione attuale
  • Slide 9
  • 9 Dependency Injection Sandro Pedrazzini Commenti Il codice precedente pone problemi di modularit e di test La dipendenza diretta, in compilazione, allelaboratore di carta di credito significa che ogni chiamata al codice, anche durante il test, esegue una transazione reale sulla carta di credito ICreditCardProcessor processor = new PaypalCreditCardProcessor();
  • Slide 10
  • 10 Dependency Injection Sandro Pedrazzini Obiettivo
  • Slide 11
  • 11 Dependency Injection Sandro Pedrazzini Factory Una factory permette di separare la classe client (BillingService) dalla classe che implementa un servizio (classi concrete di CreditCardProcessor e TransactionLog) Una factory semplice utilizza alcuni metodi static per stabilire quale implementazione collegare a una data interface
  • Slide 12
  • 12 Dependency Injection Sandro Pedrazzini Factory (2) public class CreditCardProcessorFactory { private static ICreditCardProcessor instance; public static void setInstance(ICreditCardProcessor processor) { instance = processor; } public static ICreditCardProcessor getInstance() { if (instance == null) { throw new IllegalStateException("Factory not initialized); } return instance; }
  • Slide 13
  • 13 Dependency Injection Sandro Pedrazzini Factory (3) public class RealBillingService implements IBillingService { public Receipt chargeOrder(Order order, CreditCard creditCard) { ICreditCardProcessor processor = CreditCardProcessorFactory.getInstance(); ITransactionLog transactionLog = TransactionLogFactory.getInstance(); try { ChargeResult result = processor.process(order.getAmount(), creditCard); transactionLog.logChargeResult(result); return... } catch (UnreachableException e) {... }
  • Slide 14
  • 14 Dependency Injection Sandro Pedrazzini Factory (4) CreditCardFactory TransactionLogFactory
  • Slide 15
  • 15 Dependency Injection Sandro Pedrazzini Factory (5) La scelta dellimplementazione di ICreditCardProcessor e ITransactionLog viene fatta attraverso le factory In questo modo si diminuisce la dipendenza esistente tra BillingService e queste classi Limplementazione dei test diventa pi semplice
  • Slide 16
  • 16 Dependency Injection Sandro Pedrazzini Unit Test public class BillingServiceTest extends TestCase { private ITransactionLog transactionLog = new InMemoryTransactionLog(); private ICreditCardProcessor processor = new FakeCreditCardProcessor(); public void setUp() { TransactionLogFactory.setInstance(transactionLog); CreditCardProcessorFactory.setInstance(processor); } @Test public void testBilling() {... } public void tearDown() { TransactionLogFactory.setInstance(null); CreditCardProcessorFactory.setInstance(null); }
  • Slide 17
  • 17 Dependency Injection Sandro Pedrazzini Unit Test (2)... @Test public void testBilling() { IBillingService billingService = new BillingService(); Order order = new PizzaOrder(100); CreditCard creditCard = new CreditCard("1234", 11, 2010); Receipt receipt = billingService.chargeOrder(order, creditCard); assertTrue(receipt.hasSuccessfulCharge()); assertEquals(100, receipt.getAmountOfCharge()); assertTrue(transactionLog.successfullyLogged()); }
  • Slide 18
  • 18 Dependency Injection Sandro Pedrazzini Commenti Codice problematico: le implementazioni vengono praticamente gestite in variabili globali (static) Se il tearDown() dovesse venir interrotto per qualche motivo, avremmo limplementazione di test che rimane nella factory e potrebbe creare problemi ad altri test Non possibile eseguire pi test in parallelo (variabili static)
  • Slide 19
  • 19 Dependency Injection Sandro Pedrazzini Commenti (2) La dipendenza nascosta nel codice Se per un motivo qualsiasi la factory venisse inizializzata in modo sbagliato, bisognerebbe attendere il primo pagamento per accorgersi del problema La cosa si complicherebbe se il numero di factory dovesse crescere
  • Slide 20
  • 20 Dependency Injection Sandro Pedrazzini Dependency Injection Con questo pattern si fa un passo ulteriore verso la separazione tra comportamento e risoluzione della dipendenza BillingService non pi responsabile della risoluzione, perch gli oggetti ICreditCardProcessor e ITransactionLog vengono passati come parametri
  • Slide 21
  • 21 Dependency Injection Sandro Pedrazzini Dependency Injection (2) Gli oggetti dipendenti vengono forniti a BillingService dallesterno, attraverso il costruttore (o attraverso un metodo set()) public BillingService(ICreditCardProcessor creditCardProcessor, ITransactionLog transactionLog) { fCreditCardProcessor = creditCardProcessor; fTransactionLog = transactionLog; }
  • Slide 22
  • 22 Dependency Injection Sandro Pedrazzini Dependency Injection (3) public class BillingService implements IBillingService { private ICreditCardProcessor fCreditCardProcessor; private ITransactionLog fTransactionLog; public BillingService(ICreditCardProcessor creditCardProcessor, ITransactionLog transactionLog) { fCreditCardProcessor = creditCardProcessor; fTransactionLog = transactionLog; } public Receipt chargeOrder(Order order, CreditCard creditCard) { try { ChargeResult result= fCreditCardProcessor.process(order.getAmount(), creditCard); fTransactionLog.logChargeResult(result); return... } catch (Exception e) {... }
  • Slide 23
  • 23 Dependency Injection Sandro Pedrazzini Dependency Injection (4) Injector
  • Slide 24
  • 24 Dependency Injection Sandro Pedrazzini Commenti Non vengono pi usate factory, quindi eliminata la dipendenza tra BilingService e factory Si possono modificare i test, eliminando setUp() e tearDown()
  • Slide 25
  • 25 Dependency Injection Sandro Pedrazzini Unit test public class BillingServiceTest { private ICreditCardProcessor processor = new FakeCreditCardProcessor(); private ITransactionLog transactionLog = new InMemoryTransactionLog(); public void testSuccessfulCharge() { Order order = new PizzaOrder(100); CreditCard creditCard = new CreditCard("1234", 11, 2010); IBillingService billingService = new BillingService(processor, transactionLog); Receipt receipt = billingService.chargeOrder(order, creditCard); assertTrue(receipt.hasSuccessfulCharge()); assertEquals(100, receipt.getAmountOfCharge()); assertTrue(transactionLog.successfullyLogged()); }
  • Slide 26
  • 26 Dependency Injection Sandro Pedrazzini Commenti Con il passaggio delle dipendenze al costruttore, per ogni nuova dipendenza si deve aggiungere un parametro. In questo modo il compilatore ci pu avvertire se nel test ci sono dipendenze da inserire: le dipendenze vengono esposte via API Ora le classi client di IBillingService devono gestire loro le dipendenze
  • Slide 27
  • 27 Dependency Injection Sandro Pedrazzini Generalizzazione Si pu andare indietro nella catena di dipendenze (classi che dipendono da unimplementazione di IBillingService) Queste classi dovranno accettare IBillingService come parametro Il punto di fermata saranno le classi top-level
  • Slide 28
  • 28 Dependency Injection Sandro Pedrazzini Generalizzazione (2) Per gestire le dipendenze nelle classi top-level utile usare un framework, che aiuti a ricostruire la gerarchia di dipendenze Ne esistono diversi Bean Container di Spring Guice PicoContainer