webentwicklung-frage-antwort-db.com.de

Konstruktoren vs. Fabrikmethoden

Welche Methode wird beim Modellieren von Klassen bevorzugt?

  1. Konstruktoren oder
  2. Fabrikmethoden

Und was wären die Überlegungen für die Verwendung eines der beiden?

In bestimmten Situationen bevorzuge ich eine Factory-Methode, die null zurückgibt, wenn das Objekt nicht erstellt werden kann. Dies macht den Code ordentlich. Ich kann einfach prüfen, ob der zurückgegebene Wert nicht Null ist, bevor ich eine alternative Aktion durchführe, im Gegensatz zum Auslösen einer Ausnahme vom Konstruktor. (Ich persönlich mag keine Ausnahmen)

Angenommen, ich habe einen Konstruktor für eine Klasse, die einen ID-Wert erwartet. Der Konstruktor verwendet diesen Wert, um die Klasse aus der Datenbank auszufüllen. Wenn ein Datensatz mit der angegebenen ID nicht vorhanden ist, löst der Konstruktor eine RecordNotFoundException aus. In diesem Fall muss ich die Konstruktion aller solcher Klassen in einen try..catch-Block einschließen.

Im Gegensatz dazu kann ich eine statische Factory-Methode für diese Klassen verwenden, die null zurückgibt, wenn der Datensatz nicht gefunden wird.

Welcher Ansatz ist in diesem Fall besser, Konstruktor oder Fabrikmethode?

153
Hemanshu Bhojak

Ab Seite 108 von Design Patterns: Elemente wiederverwendbarer objektorientierter Software von Gamma, Helm, Johnson und Vlissides.

Verwenden Sie das Factory-Method-Muster, wenn

  • eine Klasse kann die Klasse der Objekte, die sie erstellen muss, nicht vorhersehen
  • eine Klasse möchte, dass ihre Unterklassen die erstellten Objekte angeben
  • klassen delegieren die Verantwortung an eine von mehreren Helfer-Unterklassen, und Sie möchten wissen, welche Helfer-Unterklasse der Delegierte ist
59
Glenn

Fragen Sie sich, was sie sind und warum haben wir sie? Sie sind beide da, um eine Instanz eines Objekts zu erstellen.

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

Bisher kein Unterschied. Stellen Sie sich nun vor, wir haben verschiedene Schultypen und möchten von ElementarySchool zu HighSchool wechseln (das von einem ElementarySchool abgeleitet ist oder das gleiche Interface ISchool wie das ElementarySchool implementiert). Die Codeänderung wäre:

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

Im Falle einer Schnittstelle hätten wir:

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

Wenn Sie diesen Code an mehreren Stellen haben, können Sie feststellen, dass die Factory-Methode recht billig ist, da Sie die Factory-Methode geändert haben (wenn Sie das zweite Beispiel mit Schnittstellen verwenden).

Und das ist der Hauptunterschied und Vorteil. Wenn Sie sich mit komplexen Klassenhierarchien beschäftigen und aus einer solchen Hierarchie dynamisch eine Instanz einer Klasse erstellen möchten, erhalten Sie den folgenden Code. Factory-Methoden benötigen dann möglicherweise einen Parameter, der der Methode angibt, welche konkrete Instanz instanziiert werden soll. Nehmen wir an, Sie haben eine MyStudent-Klasse und müssen das entsprechende ISchool-Objekt instanziieren, damit Ihr Schüler ein Mitglied dieser Schule ist. 

ISchool school = SchoolFactory.ConstructForStudent(myStudent);

Jetzt haben Sie eine Stelle in Ihrer App, die Geschäftslogik enthält, die bestimmt, welches ISchool-Objekt für verschiedene IStudent-Objekte instanziiert werden soll.

Für einfache Klassen (Wertobjekte usw.) ist der Konstruktor jedoch in Ordnung (Sie möchten Ihre Anwendung nicht übersteuern), für komplexe Klassenhierarchien ist jedoch die Factory-Methode eine bevorzugte Methode. 

Auf diese Weise folgen Sie dem ersten Konstruktionsprinzip aus dem gang of four-Buch "Programm zu einer Schnittstelle, nicht einer Implementierung".

175
David Pokluda

Sie müssen lesen (wenn Sie Zugriff haben) Effektives Java 2Element 1: Berücksichtigen Sie statische Factory-Methoden anstelle von Konstruktoren.

Vorteile der statischen Fabrikmethode:

  1. Sie haben Namen.
  2. Sie müssen nicht jedes Mal ein neues Objekt erstellen, wenn sie aufgerufen werden.
  3. Sie können ein Objekt eines beliebigen Subtyps ihres Rückgabetyps zurückgeben.
  4. Sie reduzieren die Ausführlichkeit der Erstellung von Instanzen mit parametrisiertem Typ.

Nachteile statischer Fabrikmethoden:

  1. Wenn Sie nur statische Factory-Methoden bereitstellen, können Klassen ohne öffentliche oder geschützte Konstruktoren nicht untergeordnet werden.
  2. Sie sind nicht leicht von anderen statischen Methoden zu unterscheiden
63
cherouvim

Standardmäßig sollten Konstruktoren bevorzugt werden, da sie einfacher zu verstehen und zu schreiben sind. Wenn Sie jedoch speziell die Konstruktions-Feinheiten eines Objekts von seiner semantischen Bedeutung entkoppeln müssen, wie sie vom Client-Code verstanden wird, sollten Sie Fabriken besser einsetzen.

Der Unterschied zwischen Konstruktoren und Fabriken ist analog zu einer Variablen und einem Zeiger auf eine Variable. Es gibt eine andere Ebene der Dereferenzierung, die einen Nachteil darstellt. Aber es gibt noch eine andere Flexibilität, die von Vorteil ist. Wenn Sie also eine Entscheidung treffen, sind Sie gut beraten, diese Kosten-Nutzen-Analyse durchzuführen.

23

Verwenden Sie eine Factory nur, wenn Sie bei der Objekterstellung eine zusätzliche Kontrolle benötigen, und dies auf eine Weise, die mit Konstruktoren nicht möglich ist.

Fabriken haben beispielsweise die Möglichkeit zum Caching.

Eine andere Möglichkeit, Fabriken zu verwenden, besteht in einem Szenario, in dem Sie nicht wissen, welchen Typ Sie erstellen möchten. Diese Art der Verwendung wird häufig in Plug-In-Factory-Szenarien beobachtet, bei denen jedes Plug-In von einer Baseclass abgeleitet werden muss oder eine Art Schnittstelle implementiert. Die Factory erstellt Instanzen von Klassen, die von der Basisklasse abgeleitet sind oder die Schnittstelle implementieren.

11
Patrick Peters

Ein Zitat aus "Effective Java", 2. Aufl., Punkt 1: Betrachten Sie statische Factory-Methoden anstelle von Konstruktoren. 5:

"Beachten Sie, dass eine statische Factory-Methode nicht mit dem Factory-Method-Muster Von Design Patterns [Gamma95, S. 107] identisch ist. Die in Beschriebene statische Factory-Methode hat keine direkte Entsprechung in Designmuster."

11
Eugen Labun

Ein konkretes Beispiel aus einer CAD/CAM-Anwendung.

Ein Schneideweg würde unter Verwendung eines Konstruktors erstellt. Es ist eine Reihe von Linien und Bögen, die einen zu schneidenden Pfad definieren. Während die Reihen von Linien und Bögen unterschiedlich sein können und unterschiedliche Koordinaten haben, kann sie leicht durch Übergeben einer Liste an einen Konstruktor gehandhabt werden.

Eine Form würde durch die Verwendung einer Fabrik entstehen. Während es eine Formklasse gibt, wird jede Form unterschiedlich eingerichtet, je nachdem, um welche Art von Form es sich handelt. Wir wissen nicht, welche Form wir initialisieren werden, bis der Benutzer eine Auswahl trifft.

7
RS Conley

Zusätzlich zu "effektive Java" (wie in einer anderen Antwort erwähnt), schlägt ein anderes klassisches Buch auch vor: 

Ziehen Sie statische Factory-Methoden (mit Namen, die die Argumente beschreiben) überladenen Konstruktoren vor. 

Z.B. schreibe nicht

Complex complex = new Complex(23.0);

aber stattdessen schreiben

Complex complex = Complex.fromRealNumber(23.0);

Das Buch geht so weit, den Complex(float)-Konstruktor als privat zu definieren, um den Benutzer zum Aufruf der statischen Factory-Methode zu zwingen.

5
blue_note

Angenommen, ich habe einen Konstruktor für eine Klasse, die einen ID-Wert erwartet. Der Konstruktor verwendet diesen Wert, um die Klasse aus der Datenbank auszufüllen.

Dieser Prozess sollte sich definitiv außerhalb eines Konstruktors befinden.

  1. Konstruktor sollte nicht auf die Datenbank zugreifen.

  2. Die Aufgabe und der Grund für einen Konstruktor besteht darin, Datenelemente initialisieren und Klasseninvariante festlegen mit Werten, die an Konstruktor übergeben werden.

  3. Für alles andere ist ein besserer Ansatz die Verwendung von statische Factory-Methode oder in komplexeren Fällen eine separate Factory- oder Builder-Klasse.

Einige Konstruktor-Richtlinien von Microsoft :

Machen Sie minimale Arbeit im Konstruktor. Konstruktoren sollten nicht viel tun, außer um die Konstruktorparameter zu erfassen. Die Kosten für andere Bearbeitungen sollten verzögert werden, bis sie erforderlich sind.

Und

Erwägen Sie die Verwendung einer statischen Factory-Methode anstelle eines Konstruktors, wenn die Semantik der gewünschten Operation nicht direkt der Konstruktion einer neuen Instanz zugeordnet wird.

3
Lightman

Manchmal müssen Sie beim Erstellen eines Objekts einige Werte/Bedingungen prüfen/berechnen. Und wenn es eine Ausnahme auslösen kann - Konstruktro ist ein sehr schlechter Weg. Also musst du so etwas tun:

var value = new Instance(1, 2).init()
public function init() {
    try {
        doSome()
    }
    catch (e) {
        soAnotherSome()
    }
}

Wo sind alle zusätzlichen Berechnungen in init (). Aber nur Sie als Entwickler wissen wirklich über dieses init () Bescheid. Und natürlich vergessen Sie es nach Monaten nur noch ... Aber wenn Sie eine Fabrik haben - tun Sie einfach alles, was Sie brauchen, um diese init () vor dem direkten Anruf zu verbergen - also keine Probleme. Bei diesem Ansatz gibt es keine Probleme mit der Erstellung und dem Speicherleck.

Jemand hat dir von Caching erzählt. Das ist gut. Sie müssen sich jedoch auch an das Flyweight-Muster erinnern, das mit Factory Way nett zu verwenden ist.

0
trashgenerator