Utilizzo di 2 costruttori: uno che inietta le dipendenze e uno che li istanzia

3

Ho iniziato a utilizzare TDD per la prima volta su un progetto che ho avviato di recente.

Ho alcuni oggetti con dipendenze e strutture che assomigliano a questo:

public class MyClass
{
    private readonly IDependency1 _dependency1;
    private readonly IDependency2 _dependency2;

    public MyClass(IDependency1 d1, IDependency2 d2)
    {
        _dependency1 = d1;
        _dependency2 = d2;
    }

    public MyClass()
    {
        _dependency1 = new Dependency1();
        _dependency2 = new Dependency2();
    }
}

Per i test io uso gli oggetti Mock per le dipendenze ma nell'implementazione a volte permetto al costruttore di creare nuovamente un oggetto concreto.

Sembra che io stia barando, ma non sono sicuro del motivo per cui è sbagliato nella pratica.

Questa è considerata una cattiva pratica? Se è così, perché?

    
posta Nick 14.05.2014 - 22:55
fonte

3 risposte

4

In primo luogo, è meglio mettere in catena i costruttori, in modo da utilizzare solo un pezzo di codice.

public MyClass() : this(new Dependency1(), new Dependency2()) { }

Questo è molto più gestibile nel tempo, in particolare se vuoi fare qualcos'altro in entrambi i costruttori.

Se questa è una buona pratica ... non è la migliore pratica, ma è perfettamente accettabile, quando non puoi o non vuoi usare Dependency Injection. È particolarmente utile quando aggiungi test a un nuovo modulo in codice legacy e vuoi evitare di riprogettare l'intero progetto.

E quando dico Dependency Injection, non intendo necessariamente un container IOC o un localizzatore di servizi. Voglio dire che se riesci a passare le dipendenze dal codice chiamante al costruttore allora fallo, anche se questo significa un po 'più di codice.

Molto meglio per separare il più possibile l'implementazione dal codice chiamante. Potresti riutilizzarlo in seguito con un'implementazione completamente diversa.

Per ulteriori informazioni, consulta il principio di inversione delle dipendenze .

    
risposta data 14.05.2014 - 23:02
fonte
2

Non farlo. Inserendo new nel secondo costruttore, stai facendo alcune cose che ti renderanno la vita più difficile nel tempo:

  • crea una dipendenza dura e in fase di compilazione tra la classe e le classi implementazione che stai creando istanziazione.

  • prendere decisioni al momento della codifica sulle classi di implementazione da inserire nella classe, il che va contro l'idea dell'iniezione di dipendenza

  • creare più codice che devi testare e mantenere

  • interrompere "non ripeterti" in un modo sottile, perché il secondo costruttore fa in codice ciò che sta facendo la tua bean factory attraverso la configurazione

Quindi non sarai colpito dal Dio dell'iniezione delle dipendenze, ma stai creando un lavoro extra per te e il tuo team.

Anche se non utilizzi i mock, faresti meglio a lasciare che il client istanzasse & iniettare le lezioni concrete da usare. Oppure scrivi un costruttore o una fabbrica e fagli prendere quelle decisioni sulle lezioni concrete.

... il test dell'acido è, quanto più piccolo, e quindi più manutenibile, è il tuo codice senza quel secondo costruttore?

(piena divulgazione: a volte trovo che abbia senso farlo, ma lo riserverei come caso speciale piuttosto che come pratica generale).

    
risposta data 14.05.2014 - 23:49
fonte
0

Il tuo secondo costruttore dovrebbe chiamare il primo. Altrimenti mi va bene.

public MyClass() : this(new Dependency1(), new Dependency2())
{
    // should be empty here
}

Nella suite di test

  • test MyClass funziona con oggetti mock (con costruttore MyClass(IDependency1, IDependency2) )
  • prova costruttore predefinito MyClass() chiama MyClass(IDependency1, IDependency2) con tipo concreto corretto

e sei a posto

    
risposta data 14.05.2014 - 23:03
fonte

Leggi altre domande sui tag