IoC Framework vs. DI Layer

2

Diciamo che abbiamo una struttura di classe come la seguente:

// implementation.ts
export class A implements IA {
    constructor(private b: IB) {}
}
export class B implements IB {
    constructor(private c: IC) {}
}
export class C implements IC {
}
// ... interface declarations

Usando un contenitore IoC, è possibile iniettare dipendenze usando annotazioni come @Inject o @AutoWired, tuttavia ritengo che ci siano due avvertenze:

  • L'uso delle annotazioni aggiunge ulteriori preoccupazioni alle mie lezioni. A, B e C dovrebbero essere responsabili per l'implementazione e non per ciò che dovrebbe essere implementato in che modo.
  • Rischiamo di incontrare errori di runtime perché il contenitore IoC non supporta i controlli in fase di compilazione se ciascuna dipendenza viene soddisfatta.

Quindi ho pensato un po 'e ho trovato un ulteriore livello responsabile dell'iniezione delle dipendenze:

// dependency-injection.ts
let impl = require("./implementation");
export class A extends impl.A {
    constructor() {
        super(new B());
}
export class B extends impl.B {
    constructor() {
        super(new B());
}
export class C extends impl.C {
}

Per instaziare A con le dipendenze iniettate nella mia applicazione all'avvio, chiamerei semplicemente new diModule.A() . Questa soluzione ha molti vantaggi:

  • non richiede alcun framework
  • supporta la verifica in fase di compilazione se una dipendenza è soddisfatta
  • separa i problemi di implementazione e cablaggio
  • è molto flessibile, cioè non vincola il modo di cablaggio

... pur mantenendo i vantaggi di un contenitore IoC che mi viene in mente:

  • consente un'iniezione sofisticata delle dipendenze
  • evita il nesting del costruttore: new A(new B(new C()))
  • durante l'aggiornamento di una dipendenza, devo cambiare una e una sola classe
  • è abbastanza semplice applicare diverse implementazioni per scopi diversi, ad esempio avendo due classi LoggerForWarnings e LoggerForErrors .

Quale di questi due approcci orientati all'aspetto preferiresti e perché? C'è un nome per il mio approccio? Ci sono ulteriori svantaggi dello strato DI o ulteriori vantaggi di un contenitore IoC?

Dopo aver deciso quale risposta accettare, cercherò di riassumere alcuni aspetti delle due risposte. Ho discusso molto con Adrian Iftode e sebbene io sia ancora critico sui contenitori IoC senza controlli di dipendenza in fase di compilazione, i suoi argomenti valevano +1, ma sfortunatamente mi manca la reputazione.

  • Christian Willman ha notato che per progetti che non superano una certa dimensione e complessità, il mio approccio è spesso realizzato senza tutta la classe foo, semplicemente collegando tutte le classi tramite iniezione del costruttore su composizione root direttamente .
  • Adrian Iftode ha osservato che i contenitori IoC possono fare molto più delle classi A , B e C - ad esempio, possono gestire la durata degli oggetti o fornire singleton. Questa funzionalità potrebbe essere aggiunta al mio esempio utilizzando fabbriche anziché costruttori nel livello DI.
  • Quello che mi sto ancora chiedendo è se l'approccio è utile anche per i progetti più grandi. Secondo me, fare direttamente l'iniezione del costruttore in main () sarà piuttosto difficile da mantenere mentre la creazione di diverse fabbriche nel livello DI potrebbe migliorare la manutenibilità mantenendo i vantaggi degli altri contenitori IoC.

Grazie mille!

    
posta bloxx 11.08.2016 - 00:14
fonte

2 risposte

2

In realtà puoi farcela con un'implementazione molto più semplice. Collega manualmente tutto insieme nella cosiddetta radice di composizione , che è solo il punto di accesso dell'applicazione.

Ovviamente è necessario essere consapevoli dell'ordine di risoluzione delle dipendenze e prima istanziare le classi che non hanno alcuna dipendenza (cioè i sink nel grafo delle dipendenze degli oggetti).

Nel tuo esempio:

function main() {
  const c: C = new C();
  const b: B = new B(c);
  const a: A = new A(b);
}

I vantaggi sono duplici. Non confondete le vostre classi con i costruttori predefiniti, e il processo di istanziazione (brutalmente semplice) rende il codice evidente ai manutentori.

    
risposta data 11.08.2016 - 04:58
fonte
0

Stai creando i cosiddetti costruttori predefiniti. Quando le persone iniziano a usare DI forniscono due costruttori: uno per iniettare le dipendenze e un default uno dove creano le dipendenze. Quando hai newing una dipendenza fai un strong accoppiamento con quella dipendenza, quindi questa non è più l'inversione di dipendenza.

    
risposta data 11.08.2016 - 00:30
fonte