Uso dell'iniezione di dipendenza in "Codice pulito" di Robert Martin

4

In Clean Code di Robert Martin, ho trovato il seguente metodo a p. 195:

private void parseSchemaElement(String element) throws ArgsException {
    char elementId = element.charAt(0);
    String elementTail = element.substring(1);
    validateSchemaElementId(elementId);
    if (elementTail.length() == 0) marshalers.put(elementId, new BooleanArgumentMarshaler());
    else if (elementTail.equals("*")) marshalers.put(elementId, new StringArgumentMarshaler());
    else if (elementTail.equals("#")) marshalers.put(elementId, new IntegerArgumentMarshaler());
    else if (elementTail.equals("##")) marshalers.put(elementId, new DoubleArgumentMarshaler());
    else if (elementTail.equals("[*]")) marshalers.put(elementId, new StringArrayArgumentMarshaler());
    else throw new ArgsException(INVALID_ARGUMENT_FORMAT, elementId, elementTail);
}

Solo poche pagine prima (p. 157), il libro sostiene l'uso di dependency injection (DI) al fine di strutturare meglio il nostro programma e facilitare il test in isolamento.

L'esempio sopra dovrebbe essere il caso in cui l'iniezione di dipendenza dovrebbe essere usata per testare la classe data in isolamento , cioè senza testare tutte le classi *ArgumentMarshaller ?

Potremmo avere un oggetto factory, che creerebbe un *ArgumentMarshaller appropriato dove necessario - questo sarebbe coerente con le raccomandazioni DI e anche facilitare il testing con mock / doubles.

.. o forse ho frainteso qualcosa e l'iniezione di dipendenza applicata qui non è una buona idea?

    
posta ThamP 27.03.2016 - 16:31
fonte

2 risposte

7

In poche parole, dipende.

Anche se io sono tutto per l'iniezione di dipendenza in classi contenenti la logica di business, per questo caso specifico e senza conoscere il contesto, anche se Marshaler s viene istanziato direttamente, sembra che l'unico lavoro che viene fatto con loro sia l'aggiunta loro fanno un dizionario basato su qualche regola, ma in realtà non eseguono alcuna operazione su di essi. E per quello sarei OK con l'istanziazione delle classi direttamente sul posto.

Se, tuttavia, volevi disaccoppiare la creazione di Marshaler s in questione, l'approccio di fabbrica è quello corretto.

L'iniezione di dipendenza è generalmente raccomandata per le classi che contengono metodi che eseguono operazioni con effetti collaterali, come scrivere su un database. In tal caso, vuoi sapere quali sono le dipendenze in modo da non sorprenderti quando un metodo work cancella improvvisamente l'intero database anche se, in base all'API pubblica della classe, non dovrebbe accedervi.

L'unico vero miglioramento che avrei per questo codice sarebbe quello di rinominare il metodo in parseSchemaElementAndAddItToMarshalerCollection .

    
risposta data 27.03.2016 - 16:50
fonte
4

Sì, puoi usare dependency injection (DI) qui, ma consideriamo come sarebbe raggiunto.

Il metodo che citi è essenzialmente una classe factory che crea il tipo corretto di marshaller basato su un input di stringa.

Quindi l'iniezione di una classe di fabbrica non ci aiuterà molto. Separa la logica in una sua classe, che potrebbe migliorare il codice se è una classe di grandi dimensioni, ma in realtà sposta solo il criminale se il blocco e gli hard link "scendono di un livello".

Per astrarre la stringa x = tipo y logica, dovremmo iniettare un dizionario di IMarshallerFactory ciascuno con una chiave stringa associata.

Questo è un approccio accurato e consente di testare la classe che consuma senza testare le classi * marshaller come si afferma.

Tuttavia, devi ancora istanziare il dizionario nella tua IoC da qualche parte, oltre a aggiungere un host di classi e interfacce di fabbrica .

A meno che il tuo codice non richieda questo livello di genericità e la possibilità di avere vari mapping di marshaller in fase di esecuzione, potrebbe essere considerato eccessivo.

    
risposta data 27.03.2016 - 19:22
fonte