Quando utilizzare un costruttore e quando utilizzare il metodo getInstance () (metodi factory statici)?


84
  1. Quando e come dovremmo usare un costruttore

    Foo bar = new Foo();
    
  2. E quando e come dovremmo usare getInstance () (metodi di fabbrica statici)

    Foo bar = Foo.getInstance();
    

Qual è la differenza tra questi due? Ho sempre usato un costruttore, ma quando dovrei usare getInstance()invece?


Stai scrivendo il corso da solo? In caso contrario, come stai chiamando che lo fornisce?
Chris B.

quindi, l'implementazione della classe stessa significa che sto implementando un pattern singleton, giusto?
zengr

Stai chiamando getInstance() o stai scrivendo un metodo chiamato getInstance()?
Chris B.

1
Se la domanda riguarda i metodi di costruzione e di fabbrica statici , suggerisco di chiarire e modificare il titolo.
Pascal Thivent

@zengr: riguardo al tuo update2, questo potrebbe essere perché non hai nominato il tuo metodo statico secondo la convenzione, che impone che dovrebbe essere chiamato Foo.newInstance(). Foo.getInstance()è una convenzione per ottenere l'istanza singleton di una classe. Dovresti correggere il tuo esempio e usare Foo.newInstance()invece.
JRL

Risposte:


97

Tutti sembrano concentrarsi sui singleton mentre penso che la domanda sia in realtà sui metodi di costruzione e di fabbrica statici .

Questo è in realtà l' elemento 1: considera i metodi di fabbrica statici invece dei costruttori di Java efficace di Joshua Bloch:

Elemento 1: considera i metodi di fabbrica statici invece dei costruttori

Il modo normale per una classe di consentire a un client di ottenere un'istanza di se stessa è fornire un costruttore pubblico. C'è un'altra tecnica che dovrebbe far parte del toolkit di ogni programmatore. Una classe può fornire un metodo factory statico pubblico , che è semplicemente un metodo statico che restituisce un'istanza della classe. Ecco un semplice esempio da Boolean(la classe primitiva in box per il tipo primitivo boolean). Questo metodo traduce un valore booleano primitivo in un Booleanriferimento a un oggetto:

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

Notare che un metodo factory statico non è lo stesso del pattern Factory Method di Design Patterns [Gamma95, p. 107]. Il metodo factory statico descritto in questo articolo non ha un equivalente diretto in Design Patterns .

Una classe può fornire ai propri client metodi factory statici invece di, o in aggiunta a, costruttori. Fornire un metodo factory statico invece di un costruttore pubblico presenta vantaggi e svantaggi.

Vantaggi (citando il libro):

  • Un vantaggio dei metodi factory statici è che, a differenza dei costruttori, hanno nomi.
  • Un secondo vantaggio dei metodi factory statici è che, a differenza dei costruttori, non sono tenuti a creare un nuovo oggetto ogni volta che vengono richiamati.
  • Un terzo vantaggio dei metodi factory statici è che, a differenza dei costruttori, possono restituire un oggetto di qualsiasi sottotipo del loro tipo restituito.
  • Un quarto vantaggio dei metodi factory statici è che riducono la verbosità della creazione di istanze di tipi parametrizzati.

Svantaggi (citando ancora il libro):

  • Il principale svantaggio di fornire solo metodi factory statici è che le classi senza costruttori pubblici o protetti non possono essere sottoclasse.
  • Un secondo svantaggio dei metodi di fabbrica statici è che non sono facilmente distinguibili da altri metodi statici.

8
L'ultimo può essere leggermente mitigato. Tendo ad avere una classe interna statica chiamata Factory e vari metodi newInstance per renderlo più chiaro quando creo metodi factory. Mi ha salvato la caccia nel tempo in passato. :)
Rich Schuler

@Qberticus la classe interna dedicata ai metodi di fabbrica è una bella idea. Lo proverò, grazie.
Dave O.

Certamente i costruttori delle classi devono essere almeno protectedper consentire la sottoclasse, ma il codice client trae un vantaggio reale dalla creazione di un nuovo oggetto e dalla chiamata al suo costruttore, rispetto alla chiamata di un metodo factory statico? Mi sembra che una chiamata a un costruttore concatenato sia semanticamente un metodo di istanza, mentre la sequenza "crea un oggetto unitializzato e chiama il suo costruttore" è semanticamente equivalente a una chiamata al metodo factory statico.
supercat

9

Hai due domande: quando dovrei chiamare un getInstance()metodo e quando dovrei crearne uno?

Se stai decidendo se chiamare un getInstance()metodo, è facile. Hai solo bisogno di leggere la documentazione della classe per scoprire quando dovresti chiamarla. Per esempio,NumberFormat fornisce un costruttore e un getInstance()metodo; il getInstance()metodo ti darà un file NumberFormat. Perché Calendar, d'altra parte, il costruttore è protetto. Devi chiamare per avernegetInstance() uno.

Se stai decidendo se creare un getInstance()metodo, devi decidere cosa stai cercando di ottenere. O non vuoi che le persone chiamino il tuo costruttore (stai creando un singleton o una fabbrica ), o non ti dispiace (come NumberFormatsopra, dove stanno inizializzando alcuni oggetti per la comodità del chiamante).


Per farla breve? Non preoccuparti di creare getInstance()metodi nel tuo codice. Se arriverà il momento in cui saranno utili, lo saprai. E in generale, se tu puoi chiamare il costruttore di una classe, probabilmente dovresti farlo, anche se la classe fornisce un getInstance()metodo.


7

Gli usi dei metodi getInstance:

Ma il più delle volte il tuo oggetto sarà un semplice POJO e l'utilizzo di costruttori pubblici è la soluzione più pratica e ovvia.

U1: getInstance da un'altra classe

Per restituire un'istanza di una classe diversa:

public class FooFactory {
    public static Foo getInstance() {
        return new Foo();
    }
}

NumberFormat.getInstancei metodi lo fanno poiché restituiscono effettivamente istanze di DecimalFormat.

U2: problemi singleton

Il pattern singleton limita molti dei vantaggi della programmazione orientata agli oggetti. I singleton hanno generalmente costruttori privati, quindi non puoi estenderli. Poiché accederai tramite il suo metodo getInstance e non farai riferimento a nessuna interfaccia, non sarai in grado di sostituirlo con un'altra implementazione.


nel caso di un pattern di fabbrica un altro nome di metodo come 'createInstance' o 'buildInstance' sarebbe molto più adatto, ma ancora un possibile caso di ciò che il richiedente potrebbe desiderare (suona ancora un po 'nebuloso e come un compito a casa per me)
jdehaan

6

Se puoi usarli entrambi, suona come un pattern singleton mal implementato .

Usa la seconda opzione se intendi avere una sola istanza della classe nel tuo sistema e rendere privato il costruttore.

Usa il primo per consentire la costruzione di diversi oggetti della classe.

MA non dare alla tua classe entrambe le possibilità.

Fai attenzione a non sovrautilizzare i singleton, usali solo se davvero deve esistere una sola istanza nel sistema, altrimenti limiteresti le possibilità di riutilizzo della tua classe in altri progetti. Sembra interessante poter chiamare getInstance da qualsiasi punto del progetto, ma ciò rende poco chiaro chi possiede effettivamente quell'istanza: nessuno e / o tutti. Se hai molti singleton in un progetto puoi scommettere che il sistema è mal progettato (di solito). I singleton dovrebbero essere usati con attenzione, si applicano gli stessi consigli che per le variabili globali.


Aggiornata la domanda, era un po 'confusa, mi dispiace
zengr

4
------> "Fai attenzione a non usare eccessivamente i singleton" <------
Bart van Heukelom

1

Un caso in cui preferisco sempre una factory statica rispetto a un normale costruttore è quando so che la costruzione dell'oggetto sarà lenta. Faccio una semplice inizializzazione sul costruttore, ma se ho bisogno di creare qualcosa di pesante userò un metodo statico e documenterò il comportamento.


0

I single sono malvagi. I problemi che ho visto che lo circondano non riguardano il riutilizzo o l'estendibilità di un sistema (anche se ho potuto vedere come potrebbe accadere), tanto più che non posso contare il numero di volte in cui ho visto bug oscuri in un sistema che derivano da singleton.

Se hai bisogno di usare un singleton, assicurati che il suo ambito sia estremamente ristretto, ovvero limita giudiziosamente il numero di altri oggetti nel tuo sistema che lo conoscono.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.