Un costruttore di classi dovrebbe mai creare oggetti di altre classi? [duplicare]

2

È sempre bene o male avere un costruttore che crea nuove istanze di classi di cui ha bisogno rispetto al passaggio di un riferimento che desideri che la nuova classe abbia?

Quindi fondamentalmente è la differenza tra:

A classA = new A();
B classB = new B(classA);

e hanno un costruttore di classe B che assegna classA al suo campo / proprietà.

rispetto a:

B classB = new B();

e

public class B{
   A classA {private set; get;}
   //constructor
   public B(){
     classA = new A();
   }
}

Il secondo esempio viola una singola responsabilità sin dalla sua creazione e assegnazione? Questa è troppa magia in quanto fa cose di cui il programmatore non è a conoscenza? Un costruttore dovrebbe mai farlo?

    
posta WDUK 09.09.2018 - 04:43
fonte

3 risposte

9

Penso che dipenda da cosa sta effettivamente facendo A e dal ruolo che ha nella vita di B. Ad esempio è del tutto normale creare un'istanza di A in B's constructor se A è solo una ArrayList o qualche altro oggetto che incapsula lo stato di B.

D'altra parte se l'istanza di A può avere un ciclo di vita non governato da B o se si può desiderare di cambiare l'implementazione di A (ad esempio durante i test) si dovrebbe iniettarlo tramite il costruttore.

Ci sono molte risorse su quando utilizzare l'iniezione di dipendenza, ad esempio questo . Esistono anche domande StackOverflow esistenti come questo .

    
risposta data 09.09.2018 - 12:12
fonte
3

I costruttori costruiscono abitualmente altri oggetti. In alcune lingue è addirittura inevitabile. Ad esempio, in C ++ un costruttore costruirà tutti gli oggetti membro di un nuovo oggetto.

Quindi non è di per sé né buono né cattivo. Dipende dalla semantica:

  • È una cattiva pratica che un costruttore crea un oggetto che non è di proprietà dell'oggetto costruito. Quindi se A è destinato a sopravvivere a B , new B() non è una buona opzione.
  • È anche una cattiva pratica se la "sub-costruzione" introdurrebbe una dipendenza indesiderata (ad esempio se il sotto oggetto potrebbe essere polimorfico e avere specializzazioni differenti). In questo caso è preferibile l'iniezione di dipendenza (fornendo l'oggetto o una fabbrica come parametro).
  • Infine, è una pessima idea, se l'oggetto sub-costruito richiederebbe un riferimento all'oggetto costruito (perché non sai cosa farà l'oggetto creato con quel riferimento a un oggetto non ancora completamente costruito).
risposta data 09.09.2018 - 17:01
fonte
1

Il problema principale con il secondo approccio è che è molto difficile da testare.

Se scrivi un test che verifica un comportamento specifico di ClassA, dipende sempre da ClassB. Se crei ClassB nel costruttore di ClassA non hai alcun controllo su di esso. Se ClassA legge la proprietà Foo di ClassB per fare un lavoro condizionale, come si controllano i diversi casi? Non hai un modo semplice per impostare il tuo test, cioè imposta la proprietà Foo sul valore che ti serve.

Se si immette ClassB nel costruttore di ClassA invece diventa improvvisamente molto più semplice. Nel test è ora possibile creare un'istanza di ClassB, specificare un valore per Foo, costruire un'istanza di ClassA e verificare il comportamento corretto. Test fatto Ripeti per altri valori Foo ...

Questo modello è chiamato iniezione di dipendenza e dovrebbe essere preferito rispetto al tuo altro approccio. Le dipendenze di costruzione di una classe direttamente nei loro costruttori è un antipattern poiché porta a effetti collaterali e rende più difficili i test.

    
risposta data 09.09.2018 - 06:58
fonte

Leggi altre domande sui tag