Quali sono i metodi di fabbrica statici?


261

Che cos'è un metodo "fabbrica statica"?


Un metodo alternativo statico di fabbrica sta usando l'iniezione di dipendenza.
CMCDragonkai,

1
@ThangPham La risposta di Jason Owen è errata perché pretende di parlare del modello del metodo di fabbrica, che è molto diverso dal modello del metodo di fabbrica statico di cui effettivamente parla. Quindi, mentre fa un buon lavoro nel rispondere alla domanda reale, non penso che possa essere accettato nel suo stato attuale, perché porta in uno schema non correlato e aumenta la confusione già incredibilmente comune sulla differenza tra i due schemi.
Theodore Murdock,

@CMCDragonkai Penso che l'iniezione di dipendenza e la fabbrica statica siano diverse. È possibile che sia necessaria una fabbrica statica anche in caso di iniezione di dipendenza per l'iniezione delle dipendenze.
Karan Khanna,

Risposte:


126

Evitiamo di fornire accesso diretto alle connessioni al database perché richiedono molte risorse. Quindi usiamo un metodo factory statico getDbConnectionche crea una connessione se siamo al di sotto del limite. Altrimenti, tenta di fornire una connessione "di riserva", fallendo con un'eccezione se non ce ne sono.

public class DbConnection{
   private static final int MAX_CONNS = 100;
   private static int totalConnections = 0;

   private static Set<DbConnection> availableConnections = new HashSet<DbConnection>();

   private DbConnection(){
     // ...
     totalConnections++;
   }

   public static DbConnection getDbConnection(){

     if(totalConnections < MAX_CONNS){
       return new DbConnection();

     }else if(availableConnections.size() > 0){
         DbConnection dbc = availableConnections.iterator().next();
         availableConnections.remove(dbc);
         return dbc;

     }else {
         throw new NoDbConnections();
     }
   }

   public static void returnDbConnection(DbConnection dbc){
     availableConnections.add(dbc);
     //...
   }
}

se ho capito bene, puoi aggiungere availableConnections.add (db) al metodo returnDbConnection (DbConnection db)?
Haifeng Zhang,

@haifzhan, non è davvero destinato a essere completo, ma va bene.
Matthew Flaschen,

@MatthewFlaschen dovrebbe anche essere diminuito totalConnections mentre la connessione viene restituita?
Rolling Stone

@Sridhar, no, è il numero di connessioni esistenti (tracciato in modo da non creare più di MAX_CONNS), non il numero in circolazione.
Matthew Flaschen,

Il metodo @MatthewFlaschen verrà catturato da sonarcube come bug del blocco se DbConnection è Chiudibile.
Awan Biru,

477

Il modello di metodo statico di fabbrica è un modo per incapsulare la creazione di oggetti. Senza un metodo factory, si sarebbe semplicemente chiamare la classe costruttore direttamente: Foo x = new Foo(). Con questo modello, si sarebbe invece chiamare il metodo di fabbrica: Foo x = Foo.create(). I costruttori sono contrassegnati come privati, quindi non possono essere chiamati se non dall'interno della classe e il metodo factory è contrassegnato in staticmodo tale da poter essere chiamato senza prima avere un oggetto.

Ci sono alcuni vantaggi in questo modello. Uno è che la fabbrica può scegliere tra molte sottoclassi (o implementatori di un'interfaccia) e restituirla. In questo modo il chiamante può specificare il comportamento desiderato tramite parametri, senza dover conoscere o comprendere una gerarchia di classi potenzialmente complessa.

Un altro vantaggio è, come hanno sottolineato Matthew e James, controllare l'accesso a una risorsa limitata come le connessioni. Questo è un modo per implementare gruppi di oggetti riutilizzabili - invece di costruire, usare e demolire un oggetto, se la costruzione e la distruzione sono processi costosi potrebbe avere più senso costruirli una volta e riciclarli. Il metodo factory può restituire un oggetto istanziato non utilizzato se ne ha uno o costruirne uno se il conteggio degli oggetti è al di sotto di una soglia inferiore o generare un'eccezione o restituire nullse è al di sopra della soglia superiore.

Secondo l'articolo su Wikipedia, più metodi di fabbrica consentono anche interpretazioni diverse di tipi di argomenti simili. Normalmente il costruttore ha lo stesso nome della classe, il che significa che puoi avere un solo costruttore con una data firma . Le fabbriche non sono così vincolate, il che significa che puoi avere due diversi metodi che accettano gli stessi tipi di argomenti:

Coordinate c = Coordinate.createFromCartesian(double x, double y)

e

Coordinate c = Coordinate.createFromPolar(double distance, double angle)

Questo può anche essere usato per migliorare la leggibilità, come osserva Rasmus.


32
Si noti che un metodo di fabbrica statico non è lo stesso del modello di Metodo di fabbrica da Modelli di disegno [Gamma95, p. 107]. Il metodo statico di fabbrica descritto in questo articolo non ha equivalenti diretti nei motivi di progettazione.
Josh Sunshine,

Il risultato per me su questa risposta è il riferimento a oggetti raggruppabili. Questo è ESATTAMENTE come sto usando il modello di metodo di fabbrica. Vengono forniti metodi di fabbrica per aiutare a controllare il ciclo di vita di un oggetto: "crea" estrae un oggetto dal pool o crea una nuova istanza se il pool è vuoto, "distrugge" lo restituisce al pool per il riutilizzo futuro.
MutantXenu,

2
Dovresti davvero usare "modello di metodo statico di fabbrica" ​​ovunque tu dica "modello di metodo di fabbrica" ​​in questo post, stai usando il termine sbagliato. Inoltre, stai collegando l'articolo di Wikipedia su un modello diverso rispetto al modello di cui stai parlando. Probabilmente il modello Metodo di fabbrica avrebbe dovuto essere chiamato modello "Interfaccia di fabbrica", poiché implica l'uso di diversi oggetti di fabbrica che implementano un'interfaccia di fabbrica per consentire a un singolo algoritmo di produrre e lavorare con istanze di un'interfaccia, accettando un oggetto factory che può produrre la sottoclasse desiderata specifica.
Theodore Murdock,

8
Sono d'accordo con @TheodoreMurdock. Stai usando il termine sbagliato. Quello di cui stai parlando è il "Metodo statico di fabbrica" ​​di Joshua Bloch ma tu usi il termine "Metodo del metodo di fabbrica" ​​di GoF. Si prega di modificarlo affinché altre persone non fraintendano.
emeraldhieu,

1
Nota che il costruttore non deve essere privato. Una classe potrebbe fornire sia metodi di fabbrica statici pubblici sia costruttori.
Kevin,

171

NOTA! "Il metodo statico di fabbrica NON è lo stesso del modello di Metodo di fabbrica " (c) Java efficace, Joshua Bloch.

Metodo Factory: "Definisci un'interfaccia per la creazione di un oggetto, ma lascia che le classi che implementano l'interfaccia decidano quale classe creare un'istanza. Il metodo Factory consente a una classe di rinviare l'istanza alle sottoclassi" (c) GoF.

"Il metodo factory statico è semplicemente un metodo statico che restituisce un'istanza di una classe." (c) Efficace Java, Joshua Bloch. Di solito questo metodo è all'interno di una particolare classe.

La differenza:

L'idea chiave del metodo statico di fabbrica è ottenere il controllo sulla creazione di oggetti e delegarlo dal metodo costruttore al metodo statico. La decisione dell'oggetto da creare è come in Abstract Factory presa fuori dal metodo (nel caso comune, ma non sempre). Mentre l'idea chiave (!) Del metodo Factory è quella di delegare la decisione su quale istanza della classe creare all'interno del metodo Factory. Ad esempio l'implementazione classica di Singleton è un caso speciale di metodo factory statico. Esempio di metodi di fabbrica statici comunemente usati:

  • valore di
  • getInstance
  • newInstance

Puoi dirmi la differenza tra il nuovo A () e A.newInstance ()? e dentro A.newInstance cosa dovremmo fare?
Shen,

69

La leggibilità può essere migliorata con metodi di fabbrica statici:

Confrontare

public class Foo{
  public Foo(boolean withBar){
    //...
  }
}

//...

// What exactly does this mean?
Foo foo = new Foo(true);
// You have to lookup the documentation to be sure.
// Even if you remember that the boolean has something to do with a Bar
// you might not remember whether it specified withBar or withoutBar.

per

public class Foo{
  public static Foo createWithBar(){
    //...
  }

  public static Foo createWithoutBar(){
    //...
  }
}

// ...

// This is much easier to read!
Foo foo = Foo.createWithBar();

Quindi ho provato a implementare il tuo esempio ma non sono sicuro di come funzioni. I due metodi createWithBar e createWithoutBar dovrebbero chiamare 2 costruttori privati ​​all'interno della classe Foo?
Essej,

@Baxtex: Sì. Ciascuno chiamerà un costruttore privato. Forse lo stesso: private Foo(boolean withBar){/*..*/} public static Foo createWithBar(){return new Foo(true);} public static Foo createWithoutBar(){return new Foo(false);}
Rasmus Faber

Penso che questa non sia "scala" molto bene. Se hai tre o più parametri, come potresti usare questa idea e creare un bel nome per il metodo?
Dherik,

@Dherik: Quindi probabilmente dovresti usare invece il modello builder: new FooBuilder (). WithBar (). WithoutFoo (). WithBaz (). Build ();
Rasmus Faber,

21
  • hanno nomi, a differenza dei costruttori, che possono chiarire il codice.
  • non è necessario creare un nuovo oggetto ad ogni invocazione: gli oggetti possono essere memorizzati nella cache e riutilizzati, se necessario.
  • possono restituire un sottotipo del loro tipo restituito - in particolare, possono restituire un oggetto la cui classe di implementazione è sconosciuta al chiamante. Questa è una funzionalità molto preziosa e ampiamente utilizzata in molti framework che utilizzano interfacce come tipo di ritorno di metodi statici di fabbrica.

da http://www.javapractices.com/topic/TopicAction.do?Id=21


18

Tutto si riduce alla manutenibilità. Il modo migliore per dirlo è ogni volta che usi la newparola chiave per creare un oggetto, stai abbinando il codice che stai scrivendo a un'implementazione.

Il modello di fabbrica ti consente di separare il modo in cui crei un oggetto da ciò che fai con l'oggetto. Quando crei tutti i tuoi oggetti utilizzando i costruttori, stai essenzialmente cablando il codice che utilizza l'oggetto a tale implementazione. Il codice che utilizza il tuo oggetto è "dipendente da" quell'oggetto. Questo potrebbe non sembrare un grosso problema in superficie, ma quando l'oggetto cambia (pensa a cambiare la firma del costruttore o subclassare l'oggetto) devi tornare indietro e ricollegare le cose ovunque.

Oggi le fabbriche sono state ampiamente spazzate via a favore dell'utilizzo dell'iniezione di dipendenza perché richiedono un sacco di codice della piastra della caldaia che risulta essere un po 'difficile da mantenere. L'iniezione delle dipendenze è sostanzialmente equivalente alle fabbriche, ma ti consente di specificare come i tuoi oggetti vengono collegati in modo dichiarativo (attraverso la configurazione o le annotazioni).


3
Stai dicendo che le fabbriche hanno bisogno di un salvataggio? ;)
John Farrell,

4
Haha! In questi tempi penso che tutti potremmo usare un piano di salvataggio ... :)
cwash,

11

Se il costruttore di una classe è privato, non è possibile creare un oggetto per la classe dall'esterno.

class Test{
 int x, y;
 private Test(){
  .......
  .......
  }
}

Non è possibile creare un oggetto per la classe precedente dall'esterno. Quindi non puoi accedere a x, y dall'esterno della classe. Allora a che serve questa classe?
Ecco la risposta: metodo FABBRICA .
Aggiungi il metodo seguente nella classe sopra

public static Test getObject(){
  return new Test();
}

Quindi ora puoi creare un oggetto per questa classe dall'esterno. Come il modo ...

Test t = Test.getObject();

Quindi, un metodo statico che restituisce l'oggetto della classe eseguendo il suo costruttore privato è chiamato metodo FACTORY
.


1
Perché la chiami "soluzione"? Dichiarare un costruttore privato non è un "problema", è un modello di progettazione.
Ojonugwa Jude Ochalifu,

1
Aggiornato. Grazie comunque
Santhosh,

Ciao @Santhosh ho una preoccupazione è Perché non lasci che il costruttore privato sia pubblico? Se non vuoi creare una sottoclasse, per me va bene, ma se non intendo creare un costruttore privato, abbiamo qualche vantaggio Static Factory Methodrispetto al costruttore pubblico?
Shen,

9

Ho pensato di aggiungere un po 'di luce a questo post su quello che so. Abbiamo usato ampiamente questa tecnica nella nostra recent android project. Invece di creating objects using new operatorte puoi anche usare static methodper creare un'istanza di una classe. Elenco dei codici:

//instantiating a class using constructor
Vinoth vin = new Vinoth(); 

//instantiating the class using static method
Class Vinoth{
  private Vinoth(){
  }
  // factory method to instantiate the class
  public static Vinoth getInstance(){
    if(someCondition)
        return new Vinoth();
  }
}

I metodi statici supportano la creazione di oggetti condizionali : ogni volta che invochi un costruttore verrà creato un oggetto ma potresti non volerlo. supponiamo che tu voglia controllare alcune condizioni solo allora vuoi creare un nuovo oggetto. Non creeresti una nuova istanza di Vinoth ogni volta, a meno che la tua condizione non sia soddisfatta.

Un altro esempio tratto da Effective Java .

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

Questo metodo traduce un valore primitivo booleano in un riferimento a un oggetto booleano. Il Boolean.valueOf(boolean)metodo ci illustra, non crea mai un oggetto. La possibilità di static factory methodsrestituire lo stesso oggetto da ripetute invocationsconsente alle classi di mantenere un controllo rigoroso su quali istanze esistono in qualsiasi momento.

Static factory methodsè che, a differenza constructors, possono restituire uno objectqualsiasi subtypedel loro tipo di ritorno. Un'applicazione di questa flessibilità è che un'API può restituire oggetti senza rendere pubbliche le loro classi. Nascondere le classi di implementazione in questo modo porta a un'API molto compatta.

Calendar.getInstance () è un grande esempio per quanto sopra, si crea a seconda della localizzazione di una BuddhistCalendar, JapaneseImperialCalendaro da un'impostazione predefinita Georgian.

Un altro esempio che potrei pensare è che Singleton pattern, quando rendi privati ​​i tuoi costruttori, crei un getInstancemetodo personale in cui ti assicuri che sia sempre disponibile solo un'istanza.

public class Singleton{
    //initailzed during class loading
    private static final Singleton INSTANCE = new Singleton();

    //to prevent creating another instance of Singleton
    private Singleton(){}

    public static Singleton getSingleton(){
        return INSTANCE;
    }
}

4

Un metodo factory un metodo che estrae l'istanza di un oggetto. Generalmente le fabbriche sono utili quando sai che hai bisogno di una nuova istanza di una classe che implementa qualche interfaccia ma non conosci la classe di implementazione.

Ciò è utile quando si lavora con gerarchie di classi correlate, un buon esempio di questo potrebbe essere un toolkit GUI. Potresti semplicemente chiamare in codice i costruttori per implementazioni concrete di ciascun widget, ma se mai volessi scambiare un toolkit con un altro avresti un sacco di posti da cambiare. Usando una fabbrica riduci la quantità di codice che dovresti cambiare.


Supponendo che la tua fabbrica restituisca un tipo di interfaccia e non la classe concreta con cui hai a che fare.
Bill Lynch,

1
Questa risposta riguarda il modello di progettazione del metodo di fabbrica e non i metodi di fabbrica statici. I metodi factory statici sono semplicemente un metodo statico pubblico che restituisce un'istanza di una classe. Vedere il capitolo 2 di Java efficace per ulteriori dettagli.
Josh Sunshine,

4

Uno dei vantaggi che deriva dalla fabbrica statica è che l'API può restituire oggetti senza rendere pubbliche le loro classi. Ciò ha portato ad API molto compatte. In java questo è ottenuto dalla classe Collections che nasconde circa 32 classi, il che rende l'API di raccolta molto compatta.


2

Un metodo factory statico è utile quando si desidera garantire che solo una singola istanza restituirà la classe concrete da utilizzare.

Ad esempio, in una classe di connessione al database, potresti voler avere una sola classe per creare la connessione al database, in modo che se decidi di passare da Mysql a Oracle, puoi semplicemente cambiare la logica in una classe e il resto dell'applicazione usa la nuova connessione.

Se si desidera implementare il pooling di database, ciò dovrebbe avvenire anche senza influire sul resto dell'applicazione.

Protegge il resto dell'applicazione dalle modifiche che è possibile apportare alla fabbrica, che è lo scopo.

Il motivo per cui è statico è se si desidera tenere traccia di alcune risorse limitate (numero di connessioni socket o handle di file), quindi questa classe può tenere traccia di quanti sono stati distribuiti e restituiti, quindi non esaurire il risorsa limitata.


2

Uno dei vantaggi dei metodi factory statici con costruttore privato (la creazione di oggetti deve essere stata limitata per le classi esterne per garantire che le istanze non vengano create esternamente) è che è possibile creare classi controllate dall'istanza. E le classi controllate dall'istanza garantiscono che non esistono due istanze distinte uguali ( a.equals (b) se e solo se a == b ) durante l'esecuzione del programma, ciò significa che è possibile verificare l'uguaglianza degli oggetti con l' operatore == invece del metodo uguale , secondo Effective java.

La capacità dei metodi statici di fabbrica di restituire lo stesso oggetto da invocazioni ripetute consente alle classi di mantenere un controllo rigoroso su quali istanze esistono in qualsiasi momento. Si dice che le classi che fanno questo siano controllate dall'istanza. Esistono diversi motivi per scrivere classi controllate dall'istanza. Il controllo dell'istanza consente a una classe di garantire che sia un singleton (elemento 3) o non affidabile (elemento 4). Inoltre, consente a una classe immutabile (elemento 15) di garantire che non esistono due istanze uguali: a.equals (b) se e solo se a == b. Se una classe offre questa garanzia, i suoi clienti possono utilizzare l'operatore == anziché il metodo equals (Object), il che può comportare un miglioramento delle prestazioni. I tipi Enum (Articolo 30) forniscono questa garanzia.

Da Effective Java, Joshua Bloch (Articolo 1, pagina 6)


1

statico

Un membro dichiarato con la parola chiave "statico".

metodi di fabbrica

Metodi che creano e restituiscono nuovi oggetti.

in Java

Il linguaggio di programmazione è rilevante per il significato di "statico" ma non per la definizione di "fabbrica".


@Victor Le risposte non devono contenere argomenti. I fatti dovrebbero essere sufficienti: se controversi, possono essere supportati da argomentazioni o citazioni. Non sono consapevole che ci sia qualcosa di controverso qui.
Marchese di Lorne,

Ho affermato che, poiché la risposta era troppo breve e in realtà non capiva bene a prima, seconda e terza occhiata, spetta comunque all'OP chiedere nuovamente. Non importa, ho cambiato idea e ho provato a rimuovere il downvote, ma non ci riesco.
Victor,

@Victor Definisce 'troppo corto'. A volte la vera risposta è semplicemente "sì", "no", "nessuno dei due" o "entrambi". "Troppo corto" è del tutto soggettivo. Ancora non capisco il tuo commento originale. Non hai bisogno di argomenti per supportare le definizioni. Per definizione. Ho modificato la mia risposta in modo che ora sia possibile rimuovere il downvote.
Marchese di Lorne,

Ovviamente è soggettivo ... tutte le risposte di StackOverflow sono soggettive, in effetti sono legate al livello di conoscenza e alla volontà di risposta dell'autore. Davvero non capisco la tua risposta, forse era troppo breve.
Victor,

@Victor Rubbish. Le questioni di fatto non sono soggettive, né lo sono nemmeno le cose che possono essere derivate inferenzialmente da fatti o assiomi. "Troppo corto" invece è soggettivo e l'ho già affrontato. Questa risposta è essenzialmente la stessa di questa , che non hai commentato. I tuoi commenti rimangono oscuri.
Marchese di Lorne,

1

L'implementazione Java contiene le classi di utilità java.util.Arrays e java.util.Collections contenenti entrambi metodi statici di fabbrica , esempi e modalità di utilizzo:

Anche la classe java.lang.String ha tali metodi factory statici :

  • String.format(...), String.valueOf(..), String.copyValueOf(...)
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.