Consigli sull'integrazione del contenitore DI / IoC in un'applicazione esistente

9

Ora mi trovo ad affrontare l'integrazione di un contenitore di inversione del controllo (IoC) in un'applicazione esistente e sto cercando alcune raccomandazioni su come ciò possa essere fatto più facilmente con l'obiettivo finale di ridurre l'accoppiamento, aumentando così la testabilità. Sebbene generalmente non classificherei la maggior parte delle classi come oggetti divini , ognuna ha troppe responsabilità e dipendenze nascoste attraverso la statica, singleton e mancanza di interfacce.

Ecco un po 'di background alcune delle sfide che devono essere affrontate:

  • L'iniezione di dipendenza viene utilizzata raramente
  • I metodi statici abbondano - sia come metodi di fabbrica che di supporto
  • I singleton sono piuttosto prevalenti
  • Le interfacce, se utilizzate, non sono troppo granulose
  • Gli oggetti spesso inseriscono dipendenze non necessarie attraverso le classi base

Il nostro intento è che la prossima volta che avremo bisogno di apportare cambiamenti in una particolare area, cercheremo di estrapolare dipendenze che, in realtà, esistono ma sono nascoste dietro globali come singoletti e statici.

Suppongo che faccia in modo che il contenitore IoC sia secondario all'introduzione dell'iniezione di dipendenza, ma mi aspetto che ci sia un insieme di pratiche e raccomandazioni che potrebbero essere seguite o considerate che ci aiuteranno a superare queste dipendenze.

    
posta Kaleb Pederson 18.01.2011 - 17:41
fonte

3 risposte

8

Per ottenere qualcosa di simile, dovrai lavorare a passi, ognuno di questi non è banale, ma può essere realizzato. Prima di iniziare, devi capire che non puoi affrettare questo processo.

  1. Definisci i principali sottosistemi dell'applicazione e un interface per ciascuno di essi. Questa interfaccia dovrebbe solo definire i metodi che altre parti del sistema useranno per parlarne. NOTA: potrebbe essere necessario prendere più di un passaggio a questo.
  2. Fornire un'implementazione wrapper dell'interfaccia che delega al codice esistente. Lo scopo di questo esercizio è di evitare di riscrivere in massa , ma di rifattorizzare il codice per usare le nuove interfacce - cioè. riducendo l'accoppiamento nel tuo sistema.
  3. Configura il contenitore IoC per creare il sistema utilizzando le interfacce e le implementazioni che hai creato. A questo punto, ti consigliamo di creare un'istanza del contenitore IoC in modo che possa far apparire l'applicazione. Cioè se ci si trova in un ambiente servlet, assicurarsi di poter ottenere / creare il contenitore nel metodo servlet init() .
  4. Fai di nuovo la stessa cosa all'interno di ogni sottosistema, questa volta quando ti rifatti, stai trasformando l'implementazione dello stub nella cosa reale che a sua volta usa le interfacce per parlare con i suoi componenti.
  5. Ripeti se necessario finché non hai un buon bilanciamento tra la dimensione del componente e la funzionalità.

Quando hai finito, gli unici metodi statici che dovresti avere nel tuo sistema sono quelli che sono veramente funzioni - per esempio guarda la classe Collections o la classe Math . Nessun metodo statico dovrebbe tentare di accedere direttamente ad altri componenti.

Questo è qualcosa che richiederà molto tempo, pianificare di conseguenza. Assicurati che mentre esegui il refactoring stai diventando più SOLIDO nel tuo approccio progettuale. All'inizio sarà doloroso. Stai modificando drasticamente il design della tua applicazione in modo iterativo.

    
risposta data 18.01.2011 - 18:38
fonte
7

Rispondi Lavorando in modo efficace con il codice legacy e segui il suo consiglio. Inizia creando isole di codice coperto e spostati gradualmente verso un'applicazione più ben strutturata. Cercare di rendere il cambiamento in massa è una ricetta per il disastro.

    
risposta data 18.01.2011 - 18:03
fonte
5

Il motivo principale dell'introduzione di IoC è disaccoppiamento dei moduli. Il problema con Java in particolare è il strong legame vincolante che dà l'operatore new , combinato con ciò significa che il codice chiamante sa esattamente quale modulo userà.

Le fabbriche sono state introdotte per spostare questa conoscenza in un posto centrale, ma alla fine si è ancora in fase di hardwire dei moduli usando new / singleton che mantiene l'associazione dura, oppure si legge in un file di configurazione e si usa reflection / Class. forName che è fragile quando refactoring.

Se non hai il target modulare, IoC non ti darà nulla.

L'introduzione dei test delle unità molto probabilmente cambierà questo aspetto, poiché sarà necessario prendere in giro moduli non sottoposti a test, e il modo più semplice per gestirli così come i moduli di produzione effettivi con lo stesso codice è usare un framework IoC per iniettare i moduli appropriati.

    
risposta data 18.01.2011 - 18:11
fonte

Leggi altre domande sui tag