Was sind statische Factory-Methoden?

260

Was ist eine "statische Fabrik" -Methode?

Freddiefujiwara
quelle
Eine alternative statische Factory-Methode ist die Verwendung der Abhängigkeitsinjektion.
CMCDragonkai
1
@ThangPham Jason Owens Antwort ist fehlerhaft, weil sie angeblich über das Factory-Methodenmuster spricht, das sich stark von dem statischen Factory-Methodenmuster unterscheidet, über das tatsächlich gesprochen wird. Obwohl es die eigentliche Frage gut beantwortet, glaube ich nicht, dass es in seinem aktuellen Zustand akzeptiert werden könnte, da es ein nicht verwandtes Muster einbringt und die ohnehin schon unglaublich häufige Verwirrung über den Unterschied zwischen den beiden Mustern erhöht.
Theodore Murdock
@CMCDragonkai Ich denke, Abhängigkeitsinjektion und statische Factory sind unterschiedlich. Eine statische Factory kann auch im Fall einer Abhängigkeitsinjektion erforderlich sein, um zu injizierende Abhängigkeiten zu instanziieren.
Karan Khanna

Antworten:

125

Wir vermeiden den direkten Zugriff auf Datenbankverbindungen, da diese ressourcenintensiv sind. Daher verwenden wir eine statische Factory-Methode getDbConnection, die eine Verbindung herstellt, wenn wir unter dem Grenzwert liegen. Andernfalls wird versucht, eine "Ersatz" -Verbindung bereitzustellen, die mit einer Ausnahme fehlschlägt, wenn keine vorhanden ist.

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);
     //...
   }
}
Matthew Flaschen
quelle
Wenn ich das richtig verstehe, können Sie der Methode returnDbConnection (DbConnection db) availableConnections.add (db) hinzufügen?
Haifeng Zhang
@haifzhan, es ist nicht wirklich beabsichtigt, vollständig zu sein, aber okay.
Matthew Flaschen
@MatthewFlaschen sollten auch die totalConnections dekrementiert werden, während die Verbindung zurückgegeben wird?
Rolling Stone
@Sridhar, nein, es ist die Anzahl der vorhandenen Verbindungen (verfolgt, damit nicht mehr als MAX_CONNS erstellt werden), nicht die Anzahl, die zirkuliert.
Matthew Flaschen
@MatthewFlaschen Ihre Methode wird von Sonarcube als Blocker-Bug abgefangen, wenn DbConnection geschlossen werden kann.
Awan Biru
476

Das statische Factory-Methodenmuster ist eine Möglichkeit, die Objekterstellung zu kapseln. Ohne eine Factory-Methode würden Sie einfach den Konstruktor der Klasse direkt aufrufen : Foo x = new Foo(). Mit diesem Muster würden Sie stattdessen die Factory-Methode aufrufen : Foo x = Foo.create(). Die Konstruktoren sind als privat markiert, sodass sie nur innerhalb der Klasse aufgerufen werden können. Die Factory-Methode ist so markiert static, dass sie aufgerufen werden kann, ohne zuvor ein Objekt zu haben.

Dieses Muster bietet einige Vorteile. Zum einen kann die Factory aus vielen Unterklassen (oder Implementierern einer Schnittstelle) auswählen und diese zurückgeben. Auf diese Weise kann der Aufrufer das gewünschte Verhalten über Parameter festlegen, ohne eine möglicherweise komplexe Klassenhierarchie kennen oder verstehen zu müssen.

Ein weiterer Vorteil besteht darin, wie Matthew und James hervorgehoben haben, den Zugriff auf eine begrenzte Ressource wie Verbindungen zu kontrollieren. Auf diese Weise können Pools wiederverwendbarer Objekte implementiert werden. Anstatt ein Objekt zu erstellen, zu verwenden und abzureißen, ist es möglicherweise sinnvoller, sie einmal zu erstellen und zu recyceln, wenn Konstruktion und Zerstörung teure Prozesse sind. Die Factory-Methode kann ein vorhandenes, nicht verwendetes instanziiertes Objekt zurückgeben, wenn es eines hat, oder eines erstellen, wenn die Objektanzahl unter einem unteren Schwellenwert liegt, oder eine Ausnahme auslösen oder zurückgeben, nullwenn sie über dem oberen Schwellenwert liegt.

Gemäß dem Artikel auf Wikipedia ermöglichen mehrere Factory-Methoden auch unterschiedliche Interpretationen ähnlicher Argumenttypen. Normalerweise hat der Konstruktor den gleichen Namen wie die Klasse, was bedeutet, dass Sie nur einen Konstruktor mit einer bestimmten Signatur haben können . Fabriken sind nicht so eingeschränkt, was bedeutet, dass Sie zwei verschiedene Methoden verwenden können, die dieselben Argumenttypen akzeptieren:

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

und

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

Dies kann auch verwendet werden, um die Lesbarkeit zu verbessern, wie Rasmus feststellt.

Jason Owen
quelle
32
Beachten Sie, dass eine statische Factory-Methode nicht mit dem Factory-Methodenmuster aus Design Patterns [Gamma95, S. 107]. Die in diesem Artikel beschriebene statische Factory-Methode hat keine direkte Entsprechung in Entwurfsmustern.
Josh Sunshine
Die Auszahlung für mich bei dieser Antwort ist der Verweis auf poolfähige Objekte. Genau so verwende ich das Factory-Methodenmuster. Zur Steuerung des Lebenszyklus eines Objekts stehen Factory-Methoden zur Verfügung: "create" zieht entweder ein Objekt aus dem Pool oder erstellt eine neue Instanz, wenn der Pool leer ist. "Destroy" gibt es zur zukünftigen Wiederverwendung an den Pool zurück.
MutantXenu
2
Sie sollten wirklich "statisches Factory-Methodenmuster" verwenden, wo immer Sie in diesem Beitrag "Factory-Methodenmuster" sagen, Sie verwenden den falschen Begriff. Außerdem verlinken Sie auf den Wikipedia-Artikel nach einem anderen Muster als dem Muster, über das Sie sprechen. Das Factory-Methodenmuster sollte wahrscheinlich als "Factory-Schnittstelle" bezeichnet werden, da mehrere Factory-Objekte verwendet werden, die eine Factory-Schnittstelle implementieren, damit ein einzelner Algorithmus Instanzen einer Schnittstelle erzeugen und mit ihnen arbeiten kann, indem ein Factory-Objekt akzeptiert wird das kann die spezifische gewünschte Unterklasse erzeugen.
Theodore Murdock
8
Ich stimme @TheodoreMurdock zu. Sie verwenden den falschen Begriff. Sie sprechen von Joshua Blochs "Static Factory Method", aber Sie verwenden den Begriff "Factory Method Pattern" von GoF. Bitte bearbeiten Sie es, damit andere Personen es nicht missverstehen.
Smaragdhieu
1
Beachten Sie, dass der Konstruktor nicht privat sein muss. Eine Klasse kann sowohl öffentliche statische Factory-Methoden als auch Konstruktoren bereitstellen.
Kevin
170

HINWEIS! "Die statische Factory-Methode ist NICHT die gleiche wie das Factory-Methodenmuster " (c) Effektives Java, Joshua Bloch.

Factory-Methode: "Definieren Sie eine Schnittstelle zum Erstellen eines Objekts, aber lassen Sie die Klassen, die die Schnittstelle implementieren, entscheiden, welche Klasse instanziiert werden soll. Mit der Factory-Methode kann eine Klasse die Instanziierung auf Unterklassen verschieben" (c) GoF.

"Die statische Factory-Methode ist einfach eine statische Methode, die eine Instanz einer Klasse zurückgibt." (c) Effektives Java, Joshua Bloch. Normalerweise befindet sich diese Methode in einer bestimmten Klasse.

Der Unterschied:

Die Schlüsselidee der statischen Factory-Methode besteht darin, die Kontrolle über die Objekterstellung zu erlangen und diese vom Konstruktor an die statische Methode zu delegieren. Die Entscheidung für das zu erstellende Objekt erfolgt wie in Abstract Factory außerhalb der Methode (im allgemeinen Fall, jedoch nicht immer). Während die Schlüsselidee (!) Der Factory-Methode darin besteht, die Entscheidung zu delegieren, welche Klasseninstanz innerhalb der Factory-Methode erstellt werden soll. Beispielsweise ist die klassische Singleton-Implementierung ein Sonderfall der statischen Factory-Methode. Beispiel für häufig verwendete statische Factory-Methoden:

  • Wert von
  • bekomme Instanz
  • newInstance
Grygoriy Gonchar
quelle
Können Sie mir den Unterschied zwischen neuem A () und A.newInstance () sagen? und innerhalb von A.newInstance, was sollen wir tun?
Shen
69

Die Lesbarkeit kann durch statische Factory-Methoden verbessert werden:

Vergleichen Sie

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.

zu

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

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

// ...

// This is much easier to read!
Foo foo = Foo.createWithBar();
Rasmus Faber
quelle
Also habe ich versucht, Ihr Beispiel zu implementieren, bin mir aber nicht sicher, wie das funktioniert. Sollen die beiden Methoden createWithBar und createWithoutBar zwei private Konstruktoren innerhalb der Foo-Klasse aufrufen?
Essej
@ Baxtex: Ja. Jeder ruft einen privaten Konstruktor auf. Vielleicht genau das gleiche: private Foo(boolean withBar){/*..*/} public static Foo createWithBar(){return new Foo(true);} public static Foo createWithoutBar(){return new Foo(false);}
Rasmus Faber
Ich denke, das ist nicht sehr gut "skaliert". Wenn Sie drei oder mehr Parameter haben, wie können Sie diese Idee verwenden und einen schönen Namen für die Methode erstellen?
Dherik
@Dherik: Dann sollten Sie wahrscheinlich stattdessen das Builder-Muster verwenden: new FooBuilder (). WithBar (). WithoutFoo (). WithBaz (). Build ();
Rasmus Faber
21
  • haben Namen, im Gegensatz zu Konstruktoren, die Code verdeutlichen können.
  • Sie müssen nicht bei jedem Aufruf ein neues Objekt erstellen. Objekte können zwischengespeichert und bei Bedarf wiederverwendet werden.
  • kann einen Subtyp ihres Rückgabetyps zurückgeben - insbesondere kann ein Objekt zurückgegeben werden, dessen Implementierungsklasse dem Aufrufer unbekannt ist. Dies ist eine sehr wertvolle und weit verbreitete Funktion in vielen Frameworks, die Schnittstellen als Rückgabetyp für statische Factory-Methoden verwenden.

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

soldat.motte
quelle
18

Alles läuft auf Wartbarkeit hinaus. Der beste Weg, dies auszudrücken, ist, wenn Sie das newSchlüsselwort zum Erstellen eines Objekts verwenden, den Code, den Sie schreiben, an eine Implementierung zu koppeln.

Mit dem Factory-Muster können Sie trennen, wie Sie ein Objekt erstellen, und was Sie mit dem Objekt tun. Wenn Sie alle Ihre Objekte mit Konstruktoren erstellen, verdrahten Sie den Code, der das Objekt verwendet, im Wesentlichen fest mit dieser Implementierung. Der Code, der Ihr Objekt verwendet, ist von diesem Objekt "abhängig". Auf den ersten Blick scheint dies keine große Sache zu sein, aber wenn sich das Objekt ändert (denken Sie daran, die Signatur des Konstruktors zu ändern oder das Objekt zu unterordnen), müssen Sie zurückgehen und die Dinge überall neu verkabeln.

Heutzutage wurden Fabriken weitgehend zugunsten der Verwendung von Dependency Injection beiseite geschoben, da sie viel Kesselplattencode erfordern, der sich als etwas schwierig herausstellt, sich selbst zu warten. Die Abhängigkeitsinjektion entspricht im Wesentlichen Fabriken, ermöglicht jedoch die Angabe, wie Ihre Objekte deklarativ miteinander verbunden werden (durch Konfiguration oder Anmerkungen).

cwash
quelle
3
Wollen Sie damit sagen, dass Fabriken eine Rettungsaktion brauchen? ;)
John Farrell
4
Haha! In der heutigen Zeit denke ich, dass wir alle eine Rettungsaktion gebrauchen könnten ... :)
cwash
11

Wenn der Konstruktor einer Klasse privat ist, können Sie kein Objekt für eine Klasse von außerhalb erstellen.

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

Wir können kein Objekt für die oben genannte Klasse von außerhalb erstellen. Sie können also nicht von außerhalb der Klasse auf x, y zugreifen. Was nützt diese Klasse dann?
Hier ist die Antwort: FACTORY- Methode.
Fügen Sie die folgende Methode in der obigen Klasse hinzu

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

Jetzt können Sie ein Objekt für diese Klasse von außerhalb erstellen. Wie der Weg ...

Test t = Test.getObject();

Daher wird eine statische Methode, die das Objekt der Klasse durch Ausführen ihres privaten Konstruktors zurückgibt, als FACTORY- Methode bezeichnet
.

Santhosh
quelle
1
Warum nennst du es eine "Lösung"? Das Deklarieren eines privaten Konstruktors ist kein "Problem", sondern ein Entwurfsmuster.
Ojonugwa Jude Ochalifu
1
Aktualisiert.
Trotzdem
Hallo @Santhosh, ich habe Bedenken, warum lässt du den privaten Konstruktor nicht öffentlich sein? Wenn Sie keine Unterklasse erstellen möchten, ist das für mich in Ordnung, aber wenn ich nicht beabsichtige, einen privaten Konstruktor zu erstellen, haben wir dann einen Vorteil Static Factory Methodgegenüber einem öffentlichen Konstruktor?
Shen
9

Ich dachte, ich werde diesem Beitrag etwas Licht auf das geben, was ich weiß. Wir haben diese Technik in unserem ausgiebig angewendet recent android project. Stattdessen creating objects using new operatorkönnen Sie auch static methodeine Klasse instanziieren. Codeauflistung:

//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();
  }
}

Statische Methoden unterstützen die bedingte Objekterstellung : Jedes Mal, wenn Sie einen Konstruktor aufrufen, wird ein Objekt erstellt, aber das möchten Sie möglicherweise nicht. Angenommen, Sie möchten eine Bedingung nur dann überprüfen, wenn Sie ein neues Objekt erstellen möchten. Sie würden nicht jedes Mal eine neue Instanz von Vinoth erstellen, es sei denn, Ihre Bedingung ist erfüllt.

Ein weiteres Beispiel aus Effective Java .

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

Diese Methode übersetzt einen booleschen Grundwert in eine boolesche Objektreferenz. Die Boolean.valueOf(boolean)Methode veranschaulicht uns, sie erstellt niemals ein Objekt. Die Möglichkeit static factory methods, dasselbe Objekt aus wiederholten Objekten zurückzugeben, invocationsermöglicht es den Klassen, jederzeit eine strikte Kontrolle darüber zu behalten, welche Instanzen vorhanden sind.

Static factory methodsist, dass sie im Gegensatz constructorsdazu einen objectbeliebigen subtypeihrer Rückgabetypen zurückgeben können. Eine Anwendung dieser Flexibilität besteht darin, dass eine API Objekte zurückgeben kann, ohne ihre Klassen öffentlich zu machen. Das Ausblenden von Implementierungsklassen auf diese Weise führt zu einer sehr kompakten API.

Calendar.getInstance () ist ein gutes Beispiel für die oben, es auf dem Lokalisierungs - A erstellt abhängig BuddhistCalendar, JapaneseImperialCalendaroder standardmäßig ein Georgian.

Ein anderes Beispiel, das ich denken könnte, ist Singleton pattern, wo Sie Ihre Konstruktoren privat machen und eine eigene getInstanceMethode erstellen , bei der Sie sicherstellen, dass immer nur eine Instanz verfügbar ist.

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;
    }
}
Thalaivar
quelle
4

Eine Factory-Methode Eine Methode, die die Instanziierung eines Objekts abstrahiert. Im Allgemeinen sind Fabriken nützlich, wenn Sie wissen, dass Sie eine neue Instanz einer Klasse benötigen, die eine Schnittstelle implementiert, die implementierende Klasse jedoch nicht kennen.

Dies ist nützlich, wenn Sie mit Hierarchien verwandter Klassen arbeiten. Ein gutes Beispiel hierfür wäre ein GUI-Toolkit. Sie könnten einfach Aufrufe an die Konstruktoren für konkrete Implementierungen jedes Widgets fest codieren, aber wenn Sie jemals ein Toolkit gegen ein anderes austauschen wollten, hätten Sie viele Möglichkeiten zum Ändern. Durch die Verwendung einer Factory reduzieren Sie die Menge an Code, die Sie ändern müssten.

Bryan Kyle
quelle
Angenommen, Ihre Factory gibt einen Schnittstellentyp zurück und nicht die konkrete Klasse, mit der Sie sich befassen.
Bill Lynch
1
Diese Antwort bezieht sich auf das Entwurfsmuster der Factory-Methode und nicht auf statische Factory-Methoden. Eine statische Factory-Methode ist einfach eine öffentliche statische Methode, die eine Instanz einer Klasse zurückgibt. Weitere Informationen finden Sie in Kapitel 2 von Effective Java.
Josh Sunshine
4

Einer der Vorteile von Static Factory besteht darin, dass diese API Objekte zurückgeben kann, ohne ihre Klassen öffentlich zu machen. Dies führte zu einer sehr kompakten API. In Java wird dies durch die Collections-Klasse erreicht, die etwa 32 Klassen verbirgt, wodurch die Collection-API sehr kompakt ist.

Rakesh Chauhan
quelle
2

Eine statische Factory-Methode ist gut, wenn Sie sicherstellen möchten, dass nur eine einzige Instanz die zu verwendende konkrete Klasse zurückgibt.

In einer Datenbankverbindungsklasse möchten Sie möglicherweise, dass nur eine Klasse die Datenbankverbindung erstellt. Wenn Sie also von MySQL zu Oracle wechseln, können Sie die Logik in einer Klasse ändern, und der Rest der Anwendung wird dies tun Verwenden Sie die neue Verbindung.

Wenn Sie das Datenbank-Pooling implementieren möchten, erfolgt dies auch ohne Auswirkungen auf den Rest der Anwendung.

Es schützt den Rest der Anwendung vor Änderungen, die Sie möglicherweise an der Fabrik vornehmen. Dies ist der Zweck.

Der Grund dafür, dass es statisch ist, ist, wenn Sie eine begrenzte Ressource (Anzahl der Socket-Verbindungen oder Dateihandles) verfolgen möchten, kann diese Klasse verfolgen, wie viele ohnmächtig gemacht und zurückgegeben wurden, damit Sie die nicht erschöpfen begrenzte Ressource.

James Black
quelle
2

Einer der Vorteile der statischen Factory-Methoden mit privatem Konstruktor (die Objekterstellung muss für externe Klassen eingeschränkt worden sein, um sicherzustellen, dass Instanzen nicht extern erstellt werden) besteht darin, dass Sie instanzgesteuerte Klassen erstellen können . Und instanzgesteuerte Klassen garantieren, dass keine zwei gleich unterschiedlichen Instanzen existieren ( a.equals (b) genau dann, wenn a == b ), während Ihr Programm ausgeführt wird. Dies bedeutet, dass Sie die Gleichheit von Objekten mit dem Operator == anstelle der Methode equals überprüfen können , nach Effective Java.

Durch die Fähigkeit statischer Factory-Methoden, dasselbe Objekt aus wiederholten Aufrufen zurückzugeben, können Klassen jederzeit streng kontrollieren, welche Instanzen vorhanden sind. Klassen, die dies tun, sollen instanzgesteuert sein. Es gibt mehrere Gründe, instanzgesteuerte Klassen zu schreiben. Durch die Instanzsteuerung kann eine Klasse garantieren, dass es sich um einen Singleton (Punkt 3) oder einen nicht instabilen (Punkt 4) handelt. Außerdem kann eine unveränderliche Klasse (Punkt 15) garantieren, dass keine zwei gleichen Instanzen existieren: a.equals (b) genau dann, wenn a == b. Wenn eine Klasse diese Garantie übernimmt, können ihre Clients den Operator == anstelle der Methode equals (Object) verwenden, was zu einer verbesserten Leistung führen kann. Aufzählungstypen (Punkt 30) bieten diese Garantie.

Von Effective Java, Joshua Bloch (Punkt 1, Seite 6)

SherlockHomeless
quelle
1

statisch

Ein Mitglied, das mit dem Schlüsselwort 'static' deklariert wurde.

Fabrikmethoden

Methoden, die neue Objekte erstellen und zurückgeben.

in Java

Die Programmiersprache ist relevant für die Bedeutung von "statisch", nicht jedoch für die Definition von "Fabrik".

Marquis von Lorne
quelle
@ Victor Antworten müssen keine Argumente enthalten. Fakten sollten ausreichen: Wenn sie kontrovers sind, können sie durch Argumente oder Zitate gestützt werden. Mir ist nicht bewusst, dass hier etwas umstritten ist.
Marquis von Lorne
Ich erklärte, weil die Antwort zu kurz war und auf den ersten, zweiten und dritten Blick wirklich nicht gut verstanden wurde, ist es sowieso Sache des OP, erneut zu fragen. Trotzdem habe ich meine Meinung geändert und versucht, die Ablehnung zu entfernen, aber ich kann nicht.
Victor
@ Victor Definiere 'zu kurz'. Manchmal lautet die eigentliche Antwort nur "Ja", "Nein", "Weder" noch "Beides". "Zu kurz" ist völlig subjektiv. Ich verstehe Ihren ursprünglichen Kommentar immer noch nicht. Sie benötigen keine Argumente, um Definitionen zu unterstützen. Per Definition. Ich habe meine Antwort so bearbeitet, dass es jetzt möglich ist, die Downvote zu entfernen.
Marquis von Lorne
Natürlich ist es subjektiv ... alle Stackoverflow-Antworten sind subjektiv, tatsächlich hängen sie mit dem Kenntnisstand und dem Willen des Autors zusammen, zu antworten. Ich verstehe deine Antwort wirklich nicht, vielleicht war sie zu kurz.
Victor
@ Victor Müll. Tatsachen sind nicht subjektiv, und es gibt auch keine Dinge, die sich aus Tatsachen oder Axiomen ableiten lassen. "Zu kurz" ist dagegen subjektiv, und ich habe es bereits angesprochen. Diese Antwort ist im Wesentlichen dieselbe wie diese , die Sie nicht kommentiert haben. Ihre Kommentare bleiben dunkel.
Marquis von Lorne
1

Die Java-Implementierung enthält die Dienstprogrammklassen java.util.Arrays und java.util.Collections. Beide enthalten statische Factory-Methoden , Beispiele dafür und deren Verwendung:

Auch die Klasse java.lang.String verfügt über solche statischen Factory-Methoden :

  • String.format(...), String.valueOf(..), String.copyValueOf(...)
Владимир Дворник
quelle