Wann wird ein Konstruktor verwendet und wann wird die Methode getInstance () verwendet (statische Factory-Methoden)?

84
  1. Wann und wie sollen wir einen Konstruktor verwenden

    Foo bar = new Foo();
  2. Und wann und wie sollen wir getInstance () verwenden (statische Factory-Methoden)

    Foo bar = Foo.getInstance();

Was ist der Unterschied zwischen diesen beiden? Ich habe immer einen Konstruktor verwendet, aber wann sollte ich getInstance()stattdessen verwenden?

zengr
quelle
Schreibst du die Klasse selbst? Wenn nicht, wie nennt man das?
Chris B.
Die Implementierung der Klasse selbst bedeutet also, dass ich ein Singleton-Muster implementiere, oder?
Zengr
Rufen Sie an getInstance()oder schreiben Sie eine Methode namens getInstance()?
Chris B.
1
Wenn es um Konstruktor- oder statische Factory-Methoden geht , schlage ich vor, den Titel zu klären und zu ändern.
Pascal Thivent
@zengr: In Bezug auf Ihr Update2 kann dies daran liegen, dass Sie Ihre statische Methode nicht gemäß der Konvention benannt haben, die vorschreibt, dass sie benannt werden soll Foo.newInstance(). Foo.getInstance()ist eine Konvention zum Abrufen der Singleton-Instanz einer Klasse. Sie sollten Ihr Beispiel korrigieren und Foo.newInstance()stattdessen verwenden.
JRL

Antworten:

96

Jeder scheint sich auf Singletons zu konzentrieren, während ich denke, dass es sich bei der Frage tatsächlich um Konstruktor- und statische Factory-Methoden handelt .

Dies ist eigentlich Punkt 1: Betrachten Sie statische Factory-Methoden anstelle von Konstruktoren von Effective Java von Joshua Bloch:

Punkt 1: Betrachten Sie statische Factory-Methoden anstelle von Konstruktoren

Die normale Möglichkeit für eine Klasse, einem Client das Abrufen einer Instanz von sich selbst zu ermöglichen, besteht darin, einen öffentlichen Konstruktor bereitzustellen. Es gibt eine andere Technik, die Teil des Toolkits jedes Programmierers sein sollte. Eine Klasse kann eine öffentliche statische Factory-Methode bereitstellen , bei der es sich einfach um eine statische Methode handelt, die eine Instanz der Klasse zurückgibt. Hier ist ein einfaches Beispiel aus Boolean(die Boxed-Primitive-Klasse für den Primitive-Typ boolean). Diese Methode übersetzt einen booleschen Grundwert in eine BooleanObjektreferenz:

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

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 .

Eine Klasse kann ihren Clients statische Factory-Methoden anstelle oder zusätzlich zu Konstruktoren bereitstellen. Die Bereitstellung einer statischen Factory-Methode anstelle eines öffentlichen Konstruktors hat sowohl Vor- als auch Nachteile.

Vorteile (zitiert das Buch):

  • Ein Vorteil statischer Factory-Methoden besteht darin, dass sie im Gegensatz zu Konstruktoren Namen haben.
  • Ein zweiter Vorteil statischer Factory-Methoden besteht darin, dass sie im Gegensatz zu Konstruktoren nicht bei jedem Aufruf ein neues Objekt erstellen müssen.
  • Ein dritter Vorteil statischer Factory-Methoden besteht darin, dass sie im Gegensatz zu Konstruktoren ein Objekt eines beliebigen Subtyps ihres Rückgabetyps zurückgeben können.
  • Ein vierter Vorteil statischer Factory-Methoden besteht darin, dass sie die Ausführlichkeit beim Erstellen parametrisierter Typinstanzen verringern.

Nachteile (zitiert immer noch das Buch):

  • Der Hauptnachteil der Bereitstellung nur statischer Factory-Methoden besteht darin, dass Klassen ohne öffentliche oder geschützte Konstruktoren nicht in Unterklassen unterteilt werden können.
  • Ein zweiter Nachteil statischer Factory-Methoden besteht darin, dass sie nicht ohne weiteres von anderen statischen Methoden unterschieden werden können.
Pascal Thivent
quelle
8
Der letzte kann etwas gemildert werden. Ich neige dazu, eine statische innere Klasse namens Factory und verschiedene newInstance-Methoden zu haben, um es klarer zu machen, wenn ich Factory-Methoden erstelle. Es hat mir in der Vergangenheit die Zeit erspart. :)
Rich Schuler
@Qberticus die innere Klasse für Fabrikmethoden ist eine gute Idee. Ich werde es versuchen, danke.
Dave O.
Sicherlich müssen die Konstruktoren von Klassen mindestens protectedUnterklassen zulassen, aber hat Client-Code einen echten Vorteil, wenn ein neues Objekt erstellt und sein Konstruktor aufgerufen wird, anstatt eine statische Factory-Methode aufzurufen? Es scheint mir, dass ein verketteter Konstruktoraufruf semantisch eine Instanzmethode ist, während die Sequenz "Unitialisiertes Objekt erstellen und seinen Konstruktor aufrufen" semantisch einem statischen Factory-Methodenaufruf entspricht.
Supercat
9

Sie haben zwei Fragen: Wann soll ich eine Methode aufrufengetInstance() und wann soll ich eine erstellen ?

Wenn Sie sich entscheiden, ob Sie eine getInstance()Methode aufrufen möchten, ist dies ganz einfach. Sie müssen nur die Klassendokumentation lesen, um herauszufinden, wann Sie sie aufrufen sollten. Zum Beispiel NumberFormatbietet einen Konstruktor und ein getInstance()Verfahren; Die getInstance()Methode gibt Ihnen eine lokalisierte NumberFormat. Für Calendar, auf der anderen Seite wird der Konstruktor geschützt. Du musst anrufengetInstance() , um einen zu bekommen.

Wenn Sie entscheiden, ob Sie eine getInstance()Methode erstellen möchten, müssen Sie entscheiden, was Sie erreichen möchten. Entweder möchten Sie nicht, dass Benutzer Ihren Konstruktor aufrufen (Sie erstellen einen Singleton oder eine Factory ), oder es macht Ihnen nichts aus (wie NumberFormatoben, wo sie einige Objekte für den Aufrufer initialisieren).


Um es kurz zu machen? Machen Sie sich keine Sorgen, wenn Sie getInstance()Methoden in Ihrem eigenen Code erstellen. Wenn sich die Zeit ergibt, in der sie nützlich sein werden, wissen Sie Bescheid. Und wenn Sie im Allgemeinen den Konstruktor einer Klasse aufrufen können , sollten Sie dies wahrscheinlich tun, selbst wenn die Klasse eine getInstance()Methode bereitstellt .

Chris B.
quelle
7

Die Verwendung für getInstance-Methoden:

Meistens ist Ihr Objekt jedoch ein einfaches POJO, und die Verwendung öffentlicher Konstruktoren ist die praktischste und naheliegendste Lösung.

U1: getInstance aus einer anderen Klasse

So geben Sie eine Instanz einer anderen Klasse zurück:

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

NumberFormat.getInstanceMethoden tun dies, da sie tatsächlich Instanzen von zurückgeben DecimalFormat.

U2: Singleton-Probleme

Das Singleton-Muster schränkt viele der Vorteile der objektorientierten Programmierung ein. Singletons haben im Allgemeinen private Konstruktoren, daher können Sie sie nicht erweitern. Da Sie über die Methode getInstance darauf zugreifen und keine Schnittstelle referenzieren, können Sie es nicht gegen eine andere Implementierung austauschen.

Krock
quelle
Im Fall eines Factory-Musters würde ein anderer Methodenname wie 'createInstance' oder 'buildInstance' viel besser passen, aber immer noch ein möglicher Fall dessen, was der Fragesteller möchte (klingt immer noch ein bisschen nebulös und wie ein paar Hausaufgaben für mich)
Jdehaan
6

Wenn Sie beide verwenden können, klingt dies wie ein schlecht implementiertes Singleton-Muster .

Verwenden Sie die zweite Option, wenn Sie nur eine einzige Instanz der Klasse in Ihrem System haben möchten, und machen Sie den Konstruktor dann privat.

Verwenden Sie die erste Option, um mehrere Objekte der Klasse zu erstellen.

ABER geben Sie Ihrer Klasse nicht beide Möglichkeiten.

Achten Sie darauf, Singletons nicht zu stark zu verwenden. Verwenden Sie sie nur, wenn wirklich nur eine Instanz im System vorhanden sein soll. Andernfalls würden Sie die Möglichkeiten der Wiederverwendung Ihrer Klasse in anderen Projekten einschränken. Es klingt interessant, getInstance von überall in Ihrem Projekt aufrufen zu können, aber das macht unklar, wem diese Instanz tatsächlich gehört: niemand und / oder alle. Wenn Sie viele Singletons in einem Projekt haben, können Sie darauf wetten, dass das System (normalerweise) schlecht ausgelegt ist. Singletons sollten mit Vorsicht verwendet werden. Es gelten die gleichen Hinweise wie für globale Variablen.

jdehaan
quelle
Aktualisiert die Frage, war ein wenig verwirrend, sorry
Zengr
4
------> "Achten Sie darauf, Singletons nicht zu stark zu verwenden" <------
Bart van Heukelom
1

Ein Fall, in dem ich immer eine statische Fabrik einem normalen Konstruktor vorziehe, ist, wenn ich weiß, dass die Objektkonstruktion langsam sein wird. Ich mache eine einfache Initialisierung auf dem Konstruktor, aber wenn ich etwas Schweres erstellen muss, verwende ich eine statische Methode und dokumentiere das Verhalten.

Guu
quelle
0

Singletons sind böse. Die Probleme, die ich im Zusammenhang damit gesehen habe, betreffen nicht die Wiederverwendung oder Erweiterbarkeit eines Systems (obwohl ich sehen konnte, wie dies auftreten könnte), sondern vielmehr, dass ich nicht zählen kann, wie oft ich obskure Fehler in einem System gesehen habe System, das aus Singletons entsteht.

Wenn Sie einen Singleton verwenden müssen, stellen Sie sicher, dass sein Umfang extrem eng ist, dh begrenzen Sie die Anzahl der anderen Objekte in Ihrem System, die davon wissen, mit Bedacht.

Rupjones
quelle