2010-12-11 6 views
27

Sappiamo tutti la differenza tra un metodo Constructor e un metodo definito dall'utente Initialize().Metodo Initialize() vs Constructor(), utilizzo corretto per la creazione di oggetti

La mia domanda si concentra sulle migliori pratiche di progettazione per la creazione di oggetti. Possiamo inserire tutto il codice Initialize() in Constructor() e viceversa (spostare tutti i codici di riscaldamento nel metodo Initialize e chiamare questo metodo da Constructor).

Attualmente, progettando una nuova classe, creo qualsiasi nuova istanza all'interno di constructor() e sposta qualsiasi altro codice di riscaldamento nel metodo Initialize().

Qual è il miglior compromesso secondo te?

risposta

23

Penso che ci siano molteplici aspetti che dovrebbero essere presi in considerazione:

  • Un costruttore deve inizializzare un oggetto in un modo che è in uno stato utilizzabile.

  • Un costruttore deve solo inizializzare un oggetto, non eseguire lavori pesanti.

  • Un costruttore non deve chiamare direttamente o indirettamente membri virtuali o codice esterno.

Quindi nella maggior parte dei casi non dovrebbe essere richiesto un metodo di inizializzazione.

Nei casi in cui l'inizializzazione implica più che mettere l'oggetto in uno stato utilizzabile (ad es. Quando è necessario eseguire lavori pesanti o devono essere chiamati membri virtuali o esterni), allora un metodo di inizializzazione è una buona idea.

+0

Ben messo. In passato mi sono anche orientato verso l'uso dei metodi 'initialize()' sui costruttori quando non istanzia direttamente il tuo oggetto, come usare un pattern factory. Pensi che questa sia una considerazione rilevante? – Ray

3

Mi sono trovato a pensare a questo un po 'di recente (quindi trovando questa domanda) e mentre non ho una risposta ho pensato di condividere i miei pensieri.

  • Costruttori idealmente 'deve solo impostare lo stato dell'oggetto, cioè: alcuni:

this.member = member;

A mio parere questo gioca bene con IOC, l'ereditarietà, i test e solo buon profumo.

Tuttavia sollevamento di carichi pesanti a volte è necessario in modo da quello che ho cercato di fare è:

  • Passo nel sollevamento di carichi pesanti.

Ciò significa astrarre che il codice di inizializzazione di un'altra classe e passaggio che in. Questo è di solito forse se il sollevamento di carichi pesanti non è davvero il tuo oggetti responsabilità, così facendo questo in realtà refactors in codice più bello.

Se questo non è possibile ed è necessario inizializzare lo stato per la classe prima dell'utilizzo, aggiungere un metodo initialse.Ciò aggiunge la dipendenza temporale nel codice, ma questo non è necessariamente una cosa negativa soprattutto quando si usano contenitori IoC:

Say CarEngine richiede un DrivingAssistComputer, e le DrivingAssistComputer deve fare inizializzazione pesante, vale a dire caricare tutti i parametri, i controlli condizioni atmosferiche, ecc. Un'altra cosa da notare è che CarEngine non interagisce direttamente con lo DrivingAssistComputer, ha solo bisogno che sia presente, facendo le sue cose sul lato. In effetti, il motore potrebbe non funzionare correttamente senza il DrivingAssistComputer che fa la sua cosa in background (cambiando qualche stato da qualche parte). Se stiamo usando CIO allora abbiamo:

// Without initialise (i.e. initialisation done in computer constructor) 
public CarEngine(FuelInjectors injectors, DrivingAssistComputer computer) { 
    this.injectors = injectors; 
    // No need to reference computer as we dont really interact with it. 
} 

... 

Quindi quello che abbiamo qui è una marcatura computer come una dipendenza, ma in realtà non usarlo argomento del costruttore. Quindi questo è brutto, ma lascia aggiungere un metodo di inizializzazione:

public CarEngine(FuelInjectors injectors, DrivingAssistComputer computer) { 
    this.injectors = injectors; 
    // This ofcourse could also be moved to CarEngine.Initialse 
    computer.Initialise(); 
} 

... 

Ancora non non è una classe coesa, ma almeno sappiamo che dipendiamo sul computer, anche se non stiamo interagendo direttamente con esso al di fuori del costruttore.

Un'altra opzione naturalmente è quello di avere un CarEngineFactory che fa:

CarEngine CreateEngine(FuelInjectors injectors) { 
    new DrivingAssistComputer().Initialise(); 
    return new CarEngine(injectors); 
} 

... 

Tuttavia, ritengo che le fabbriche e il CIO solo confondere la matrice quindi vorrei andare per la seconda opzione.

Mi piacerebbe sentire alcuni pensieri su questo.

Modifica 1: Un'altra opzione che ho perso sopra sta avendo il metodo di inizializzazione ma lo spostamento di questa invocazione al modulo di inizializzazione IoC. Quindi la creazione e l'inizializzazione sono ancora in qualche modo incapsulate.

+0

+1 per 'passare il lavoro pesante' - questo ha senso per me –

Problemi correlati