2009-03-10 20 views
132

Quando modellazione classi, qual è il modo preferito di inizializzazione:Costruttori vs metodi di fabbrica

  1. Costruttori, o metodi
  2. fabbrica

E quali sarebbero le considerazioni per l'utilizzo di una di esse ?

In determinate situazioni, preferisco avere un metodo factory che restituisce null se l'oggetto non può essere costruito. Questo rende il codice pulito. Posso semplicemente verificare se il valore restituito non è nullo prima di intraprendere un'azione alternativa, in contrasto con il lancio di un'eccezione da parte del costruttore. (Personalmente non mi piacciono le eccezioni)

Dire, ho un costruttore su una classe che si aspetta un valore di identificazione. Il costruttore utilizza questo valore per popolare la classe dal database. Nel caso in cui non esista un record con l'ID specificato, il costruttore lancia una RecordNotFoundException. In questo caso dovrò racchiudere la costruzione di tutte queste classi all'interno di un blocco try..catch.

In contrasto con questo, posso avere un metodo factory statico su quelle classi che restituiscono null se il record non viene trovato.

Quale approccio è migliore in questo caso, metodo costruttore o stabilimento?

risposta

60

Da pagina 108 del Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson, and Vlissides.

Utilizzare il modello Factory Method quando

  • una classe non può anticipare la classe di oggetti è necessario creare
  • una classe vuole sue sottoclassi per specificare gli oggetti crea
  • classi delegare la responsabilità a una delle diverse sottoclassi di helper e si desidera localizzare la conoscenza di quale sottoclasse helper è il delegato
+17

Il metodo di fabbrica statico è diverso dal modello di progettazione GoF - Modello metodo di fabbrica. http://stackoverflow.com/questions/929021/what-are-static-factory-methods-in-java –

+0

Si prega di non confrontare con il modello metodo di fabbrica di modelli di progettazione GoF. –

+80

questo non mi spiega nulla – Sushant

23

Per impostazione predefinita, i costruttori devono essere preferiti, perché sono più semplici da comprendere e scrivere. Tuttavia, se hai specificamente bisogno di disaccoppiare le sottigliezze costruttive di un oggetto dal suo significato semantico come inteso dal codice client, starai meglio usando le fabbriche.

La differenza tra costruttori e fabbriche è analoga, ad esempio, a una variabile ea un puntatore a una variabile. C'è un altro livello di riferimento indiretto, che è uno svantaggio; ma c'è anche un altro livello di flessibilità, che è un vantaggio. Quindi, mentre fai una scelta, ti consigliamo di fare questa analisi costi-benefici.

+13

Quindi, (stile TDD) si dovrebbe iniziare con i costruttori come il modo più semplice per portare a termine il lavoro. E poi refactoring alle fabbriche una volta che inizi a ricevere odori di codice (come la logica condizionale ripetuta che determina quale costruttore chiamare)? – AndyM

+0

Absolutely @ AndyM –

145

Chiediti cosa sono e perché li abbiamo. Entrambi sono lì per creare un'istanza di un oggetto.

ElementarySchool school = new ElementarySchool(); 
ElementarySchool school = SchoolFactory.Construct(); // new ElementarySchool() inside 

Nessuna differenza finora. Ora immagina di avere vari tipi di scuola e vogliamo passare dall'uso di ElementarySchool a HighSchool (che è derivato da una scuola elementare o implementa la stessa interfaccia ISchool della scuola elementare).La modifica del codice sarebbe:

HighSchool school = new HighSchool(); 
HighSchool school = SchoolFactory.Construct(); // new HighSchool() inside 

In caso di un'interfaccia che avrebbe:

ISchool school = new HighSchool(); 
ISchool school = SchoolFactory.Construct(); // new HighSchool() inside 

Ora, se si dispone di questo codice in più posizioni si può vedere che usando il metodo factory potrebbe essere piuttosto a buon mercato perché una volta modificato il metodo di produzione, hai finito (se usiamo il secondo esempio con le interfacce).

E questa è la principale differenza e vantaggio. Quando si inizia a gestire gerarchie di classi complesse e si desidera creare dinamicamente un'istanza di una classe da tale gerarchia si ottiene il seguente codice. I metodi di fabbrica possono quindi prendere un parametro che indica al metodo quale istanza concreta creare un'istanza. Diciamo che hai una lezione di MyStudent e devi istanziare l'oggetto ISchool corrispondente in modo che il tuo studente sia membro di quella scuola.

ISchool school = SchoolFactory.ConstructForStudent(myStudent); 

Ora avete un posto nel vostro app che contiene la logica di business che determina quale oggetto iSchool istanziare per diversi oggetti IStudent.

Quindi, per il costruttore di classi semplici (oggetti di valore, ecc.) Va benissimo (non si desidera eseguire l'ipogenerazione dell'applicazione), ma per le gerarchie di classi complesse il metodo di produzione è preferibile.

In questo modo si segue il primo principio di progettazione dal gang of four book "Programma su un'interfaccia, non un'implementazione".

+1

Anche se pensi che sia una classe semplice, c'è la possibilità che qualcuno abbia bisogno di estendere la tua classe semplice, quindi il metodo factory è ancora migliore. Per esempio. puoi iniziare con ElementarySchool ma in seguito qualcuno (incluso te stesso) può estenderlo con PrivateElementarySchool e PublicElementarySchool. – jack

+5

questa dovrebbe essere la risposta accettata – am05mhz

+1

@David, buona risposta, ma è possibile espandere un esempio in cui ogni implementazione dell'interfaccia potrebbe richiedere parametri diversi per la costruzione. Ecco un esempio stupido: 'Sandwich IFood = nuovo Sandwich (Cheese chz, Meat meat);' e 'Ifood soup = new Soup (brodo di brodo, verdure veg);' Come può aiutare la fabbrica o il costruttore qui? –

11

Utilizzare una fabbrica solo quando è necessario un controllo supplementare con la creazione dell'oggetto, in un modo che non può essere eseguito con i costruttori.

Le fabbriche hanno la possibilità di memorizzare la cache ad esempio.

Un altro modo di utilizzare le fabbriche è in uno scenario in cui non si conosce il tipo che si desidera costruire. Spesso si vede questo tipo di utilizzo in scenari di plug-in factory, in cui ogni plugin deve derivare da una baseclass o implementare un qualche tipo di interfaccia. Il factory crea istanze di classi che derivano dalla baseclass o che implementano l'interfaccia.

54

È necessario leggere (se si ha accesso a) Effective Java 2Elemento 1: considerare i metodi di fabbrica statici anziché i costruttori.

statici metodi di fabbrica vantaggi:

  1. Hanno nomi.
  2. Non è necessario creare un nuovo oggetto ogni volta che vengono richiamati.
  3. Possono restituire un oggetto di qualsiasi sottotipo del tipo restituito.
  4. Riducono la verbosità di creazione di istanze di tipi parametrizzati.

statici metodi di fabbrica svantaggi:

  1. Nel fornire solo i metodi factory statici, classi senza costruttori pubblici o protetti non possono essere sottoclasse.
  2. non sono facilmente distinguibili da altri metodi statici
+3

Questo mi sembra piuttosto un bug grave in Java, quindi un problema di OOD generale. Esistono numerosi linguaggi OO che non hanno * solo * costruttori, tuttavia la sottoclasse funziona bene. –

+0

@cherouvim perché principalmente il codice è scritto usando Costruttori se '(i metodi di fabbrica sono migliori dei Costruttori. (Articolo 1)) Effettiva java' – UnKnown

+0

Buoni punti. È comunque specifico di Java. È possibile creare un caso per un linguaggio che rende i metodi di fabbrica distinguibili da altri metodi statici. – OCDev

6

Un esempio concreto da un'applicazione CAD/CAM.

Un percorso di taglio sarebbe stato realizzato utilizzando un costruttore. È una serie di linee e archi che definiscono un percorso da tagliare. Mentre la serie di linee e archi può essere diversa e avere coordinate diverse, può essere gestita facilmente passando una lista in un costruttore.

Una forma verrebbe creata utilizzando una fabbrica. Perché mentre c'è una classe di forma ogni forma dovrebbe essere configurata in modo diverso a seconda del tipo di forma che è. Non sappiamo quale forma stiamo per inizializzare finché l'utente non effettua una selezione.

11

Una citazione da "Java efficace", 2a ed., Elemento 1: considerare metodi di factory statici invece di costruttori, p. 5:

"Si noti che un metodo factory statico non è lo stesso del modello Factory Method da Design Patterns [Gamma95, p 107.] Il metodo factory statico descritto in questo elemento non ha equivalenti in. Modelli di progettazione."

3

Dire, ho un costruttore su una classe che si aspetta un valore id. Il costruttore utilizza questo valore per popolare la classe dal database.

Questo processo deve essere sicuramente all'esterno di un costruttore.

  1. Il costruttore non deve accedere al database.

  2. Il compito e la ragione di un costruttore è quello membri dati di inizializzazione e stabilire invariante di classe utilizzando valori passati in costruzione.

  3. Per tutto il resto un approccio migliore è quello di utilizzare metodo factory statici o in casi più complessi un separato fabbrica o costruttore classe.

Some constructor guide lines from Microsoft:

fare un lavoro minimo nel costruttore. I costruttori non dovrebbero fare molto lavoro se non quello di acquisire i parametri del costruttore. Il costo di qualsiasi altra elaborazione dovrebbe essere ritardato fino a quando richiesto.

E

considerare l'utilizzo di un metodo factory statico invece di un costruttore se la semantica del l'operazione desiderata non corrispondono direttamente alla costruzione di una nuova istanza.

Problemi correlati