Quale di questi è la migliore strategia per l'iniezione di dipendenza?

3

Sto lavorando su un progetto Java che utilizza un framework di integrazione delle dipendenze creato dalla società stessa. Il framework applica la seguente convenzione di denominazione: supponi di avere una classe Foo che dipende da un'interfaccia chiamata org.company.IBar :

class Foo {
   @Injection
   private IBar bar;

   ...
}

allora il framework cercherà una classe chiamata org.company.implementation.Bar , creerà una nuova istanza di quella classe e quindi assegnerà all'attributo Foo.bar . Il framework consente comunque alcune personalizzazioni. In quell'annotazione @Injection , puoi dichiarare il tuo stabilimento, con il quale puoi applicare le tue convenzioni. Ma ogni volta che vuoi usare un certo factory, devi dichiararlo esplicitamente nell'annotazione sull'attributo da iniettare.

Questa strategia, tuttavia, renderà le tue classi strettamente accoppiate l'una all'altra, perché quando dichiari una dipendenza su un'interfaccia, ti stai già impegnando in una determinata implementazione. Così, ho deciso di implementare il mio stabilimento per eseguire manualmente l'iniezione di dipendenza. È fondamentalmente una classe che istanzia tutti gli oggetti dell'applicazione e li collega insieme. Ogni oggetto ha il suo ambito (singleton o prototipo) controllato dalla fabbrica. Pensa a un file di configurazione IoC Spring (ma scritto in Java, anziché XML).

I miei colleghi non hanno approvato questa decisione. La loro tesi è che la fabbrica che ho creato "ha troppe responsabilità" e che l'istanziazione di ogni oggetto deve essere lasciata al framework. Se è necessario utilizzare un'altra convenzione, è necessario creare fabbriche personalizzate per ogni classe (come descritto sopra). Sicuramente, secondo loro, non ci dovrebbe essere una singola fabbrica in cui tutti gli oggetti sono istanziati.

Sono strongmente in disaccordo con le loro argomentazioni. La fabbrica ha una sola responsabilità : creare il grafico dell'oggetto. Se dovesse sorgere la necessità di modificare quel grafico, c'è solo una classe che dovrà cambiare. Ma potrei mancare qualcosa qui. Quali sono i pro e i contro di ciascuna strategia?

    
posta Otavio Macedo 20.10.2011 - 14:40
fonte

2 risposte

1

Sono d'accordo sul fatto che il modello di una singola implementazione "predefinita" o una fabbrica per classe sia troppo rigida.

Vedo due potenziali problemi con il tuo approccio:

  • il cablaggio di tutto in Java rende scomode le modifiche alla configurazione - è necessario ricompilare e ridistribuire (parte) l'app ogni volta,
  • una fabbrica per istanziare l'intero oggetto grafico può essere a grana troppo grossa (a seconda delle dimensioni del grafico dell'oggetto). Se il grafico è enorme, la logica di fabbrica diventa difficile da mantenere. Questo è il motivo per cui potrebbe essere meglio avere fabbriche separate, anche se non necessariamente una per classe. Trova una comoda via di mezzo, raggruppando classi strettamente correlate / dipendenti.

    Il principio di responsabilità singola è buono da seguire, ma IMO il punto principale è creare (e mantenere) classi di dimensioni gestibili. Si noti che le responsabilità hanno diversi livelli di astrazione. Ciò che può sembrare una singola responsabilità a un livello superiore, è suddiviso in diversi compiti distinti a un livello inferiore. Posso definire una "singola responsabilità" per la mia classe: "soddisfare i bisogni del cliente" e creare una classica classe di Dio, che viola chiaramente l'SRP: -)

risposta data 20.10.2011 - 15:00
fonte
1

Hai esaminato l'utilizzo di Guice ? È una struttura di iniezione delle dipendenze come quella che hai descritto. Tuttavia, consente di creare diversi modelli di iniezione che possono specificare un insieme di interfacce per i mapping di implementazione.

public class BillingModule extends AbstractModule {
  @Override 
  protected void configure() {
    bind(TransactionLog.class).to(DatabaseTransactionLog.class);
    bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
    bind(BillingService.class).to(RealBillingService.class);
  }
}

Link al loro esempio di implementazione .

Sembra una buona via di mezzo tra le due opzioni che hai descritto. Gli oggetti di classe vengono iniettati per non dover sapere esplicitamente quale classe è responsabile di eseguire l'iniezione. E come utente del framework, non devi fare il sollevamento pesante per garantire che il grafico dell'oggetto sia istanziato correttamente.

    
risposta data 20.10.2011 - 14:55
fonte

Leggi altre domande sui tag