Warum ist das Entwurfsmuster für Factory-Methoden nützlicher, als Klassen zu haben und sie einzeln aufzurufen?

32

Aus den "Gang of Four" -Designmustern ergibt sich die Factory-Methode:

class Factory(product)
  case product
  when a
    new A
  when b
    new B
  when c
    new C
end

new Factory(a)

Warum ist das sinnvoller als mit drei Klassen, a, b, und cund sie einzeln aufrufen?

alt
quelle
1
Was meinst du genau? Warum nicht alle drei instanziieren? Meinst Du das?
Neil
1
@Neil Nein, im Factory-Pattern existieren alle Klassen als Geschwister. Warum die Fabrik anrufen, um indirekt auf die Klassen a, b, c zuzugreifen?
Alt
3
das sieht für mich nicht nach dem Muster der Factory-Methode aus, wenn überhaupt etwas, das der abstrakten Factory näher kommt
jk.
2
Weil Sie zur Entwurfszeit nicht wissen, welche der 3 Klassen Sie instanziieren müssen.
MrWhite
2
@jk: Nein, das tut es wirklich nicht. programmers.stackexchange.com/questions/81838/…
pdr

Antworten:

54

Weil dein Beispiel nicht kompliziert genug ist. Für solch ein einfaches Szenario ist es nicht einmal sinnvoll, ein erweitertes Muster zu verwenden.

Wenn Sie jedoch mehr als das Produkt wissen müssen, um A, B oder C zu konstruieren, und keinen direkten Zugriff auf dieses Wissen haben, ist es nützlich. Dann nutzen Sie die Fabrik als Wissenszentrum für die Herstellung der benötigten Objekte.

Vielleicht benötigen diese Objekte einen Verweis auf ein Objekt X, das die Factory bereitstellen kann, aber Ihr Code an der Stelle, an der Sie A, B oder C konstruieren möchten, kann oder sollte keinen Zugriff auf X haben. Vielleicht, wenn Sie X haben Sie erstellen A und B, aber wenn Sie Y-Typ haben, dann erstellen Sie C.

Bedenken Sie auch, dass einige Objekte möglicherweise 20 Abhängigkeiten benötigen, um erstellt zu werden. was dann? Es könnte problematisch sein, diese Abhängigkeiten an einem Ort zu suchen, an dem sie nicht zugänglich sein sollten.

Mateusz
quelle
13
+1 um zu verdeutlichen, dass Factory-Muster nicht immer der beste Ansatz ist.
Neil
1
Weil dein Beispiel nicht kompliziert genug ist. Für solch ein einfaches Szenario ist es nicht einmal sinnvoll, ein erweitertes Muster zu verwenden. Was würden Sie in diesem Fall tun? Inline die bedingte Konstruktion?
pdr
Es kann nur eine Methode sein, die das Produkt nimmt und das zurückgibt, was Sie benötigen, um es wiederverwendbar zu machen, sodass es nicht inline sein muss. Wenn eine solche Methode zu etwas Größerem heranwächst oder in mehreren anderen Klassen verwendet wird, können Sie sie in eine andere Klasse umwandeln.
Mateusz
Das Muster wird aus einem bestimmten Grund als Factory-Methode bezeichnet. Die Methode muss nicht in einer anderen Klasse sein, um eine Factory-Methode zu sein (obwohl dies häufig der Fall ist).
pdr
Ich habe die "Methode" darin verpasst, also bist du der richtige Herr.
Mateusz
23

Ein Fabrikmuster ist normalerweise komplexer. Eine Factory entscheidet nach bestimmten Kriterien, welche Instanz erstellt / zurückgegeben werden soll. Wenn Sie die Factory nicht verwenden, wird dieser Code an mehreren Stellen im Code wiederholt verwendet.

Betrachten Sie als Beispiel Folgendes: Sie müssen Daten aus einer Datenbank laden, haben jedoch eine zentrale Datenbank für die Integration mit vielen Daten und eine kleinere im Speicher auf jedem Entwicklungs-PC. In Ihrem Code fordern Sie eine Factory auf, ein DB-Handle zu erhalten, und die Factory gibt eines davon zurück, abhängig von z. B. einer Konfigurationsdatei.

Andy
quelle
20

Das Factory-Methodenmuster abstrahiert den Entscheidungsprozess von der aufrufenden Klasse. Dies hat mehrere Vorteile:

Wiederverwendung. Wenn ich an vielen Stellen instanziieren möchte, muss ich meinen Zustand nicht wiederholen. Wenn ich also eine neue Klasse hinzufüge, riskiere ich nicht, eine zu verpassen.

Unit-Testbarkeit. Ich kann 3 Tests für die Factory schreiben, um sicherzustellen, dass sie die richtigen Typen unter den richtigen Bedingungen zurückgibt. Dann muss meine aufrufende Klasse nur getestet werden, um festzustellen, ob sie die Factory aufruft, und dann die erforderlichen Methoden für die zurückgegebene Klasse. Es muss nichts über die Implementierung der Fabrik selbst oder die konkreten Klassen wissen.

Erweiterbarkeit. Wenn jemand entscheidet, dass wir dieser Factory eine neue Klasse D hinzufügen müssen, muss keiner der aufrufenden Codes, weder Unit-Tests noch Implementierung, mitgeteilt werden. Wir erstellen einfach eine neue Klasse D und erweitern unsere Fabrikmethode. Dies ist die eigentliche Definition des Open-Closed-Prinzips .

Sie können sogar eine neue Factory-Klasse erstellen und diese Hot-Swap-fähig machen, wenn die Situation dies erfordert - beispielsweise, wenn Sie Klasse D beim Testen ein- und ausschalten möchten. Ich bin nur einmal auf diese Situation gestoßen, aber sie war äußerst nützlich.

Wie bereits erwähnt, ist das Factory-Pattern nicht immer der richtige Weg. Aber wo immer Sie bedingte Instanziierung sehen, sollten Sie einen Moment darüber nachdenken.

pdr
quelle
14

Die wichtigsten Vorteile des Factory-Musters sind zweierlei:

  1. Die Stellen, an denen eine Implementierung des Produkts erforderlich ist, müssen nicht wissen, wie sie erstellt werden. Die Fabrik hält diese Informationen.

    Möchten Sie wissen, welche Argumente an den jeweiligen Konstruktor übergeben werden sollen? Oder welche Abhängigkeiten musst du einspritzen? Oder wie kann die Implementierungsklasse bei der Datenbank registriert werden, nachdem sie vollständig konfiguriert wurde? Nein? Lassen Sie die Fabrik sich um all das Zeug kümmern.

  2. Die Stellen, die eine Implementierung des Produkts benötigen, müssen zum Zeitpunkt der Modulbeschreibung (dh zum Zeitpunkt der Kompilierung) nicht wissen, wie die Implementierungsklasse heißt.

    Es amuss also nichts damit zu tun haben A; Das „was zu bauen ist“ kann anhand der gewünschten nicht-funktionalen Eigenschaften und nicht nur des Namens beschrieben werden. Das ist viel flexibler.

Der Nachteil ist, dass Sie bei der Verwendung einer Fabrik komplexer werden, wenn Sie wissen, was zu machen ist und wie es zu tun ist. Die Lösung dafür ist jedoch einfach: Verwenden Sie keine Fabrik, wenn sie keinen Sinn ergibt!

Donal Fellows
quelle
2

Ich würde gerne über Designmuster nachdenken, in denen Klassen als „Menschen“ verstanden werden, und Muster sind Wege, wie Menschen miteinander reden.

Für mich ist das Fabrikmuster also wie eine Personalagentur. Sie haben jemanden, der eine variable Anzahl von Arbeitern benötigt. Diese Person kann einige Informationen kennen, die sie in den Leuten benötigt, die sie anstellt, aber das ist es.

Wenn sie also einen neuen Mitarbeiter brauchen, rufen sie das Personalbüro an und sagen ihnen, was sie brauchen. Um jemanden einzustellen, müssen Sie eine Menge Dinge wissen - Vorteile, Berechtigungsüberprüfung usw. Aber die Person, die anstellt, muss nichts davon wissen - die Personalagentur kümmert sich um all das.

Auf die gleiche Weise ermöglicht die Verwendung einer Factory dem Konsumenten, neue Objekte zu erstellen, ohne die Details zu kennen, wie sie erstellt wurden oder welche Abhängigkeiten sie haben - er muss nur die Informationen angeben, die er tatsächlich haben möchte.

Höflichkeit

Premraj
quelle
1

Das Factory-Muster ist das am häufigsten verwendete und am häufigsten verwendete Entwurfsmuster.

Ich bin auf zahlreiche Fälle gestoßen, in denen eine Factory-Klasse codiert ist, wenn ein einfacher Konstruktor angemessen wäre.

Verwenden Sie keine Werksklasse, es sei denn: -

  • Sie sind auf eine externe Ressource angewiesen, wissen aber noch nicht genau, welche.
  • Der Bau ist teuer und Sie möchten einmal bauen und mehrmals wiederverwenden.
  • Das Erstellen einer neuen Instanz hängt davon ab, welche Instanzen bereits erstellt wurden (z. B. Sie können nur fünf Verbindungen haben, oder Sie sollten eine Verbindungs-ID Nummer eins mehr als die zuletzt verwendete Nummer verwenden).
James Anderson
quelle
0

Verwenden Sie die Factory-Methode, wenn Sie eine Unterklasse instanziieren und der Client-Code nicht dafür verantwortlich sein soll, zu entscheiden, welche bestimmte Unterklasse instanziiert wird.

Dies ist nützlich, da Sie dadurch den Clientcode nicht ändern müssen, wenn Sie ändern müssen, welche Klasse instanziiert wird. Das Ändern von vorhandenem Code ist eine schlechte Praxis, da er normalerweise fehleranfällig ist.

Ein Beispiel wären Unterklassen, in denen die Daten in aufsteigender Reihenfolge, jedoch auf unterschiedliche Weise sortiert werden. Jeder Weg ist für eine bestimmte Art von Daten optimal. Beispiel: teilweise sortierte Daten, Daten, die Zahlen usw. sind. Der Client-Code ist eine Klasse, die nur das Drucken von Daten verarbeitet. Ein Code, der entscheidet, welche Sortierklasse in der Client-Klasse instanziiert wird, würde sie zu einer komplexen Klasse machen. Mit anderen Worten, Sie haben in diesem Fall mehr als eine Verantwortung, entscheiden, welche Sortierklasse optimal ist, und drucken Daten. Durch Einfügen des Codes, der entscheidet, welche Sortierklasse instanziiert wird, in eine Factory-Klasse werden die Bedenken getrennt, sodass Sie die Client-Klasse nicht jedes Mal ändern müssen, wenn Sie die instanziierte Sortierunterklasse ändern müssen.

Es ist eine Möglichkeit, Ihren Arsch zu bedecken. Wenn Sie voraussehen können, wie oder welche Klasse instanziiert wird, ist die Verwendung von Factory-Klassen sinnvoll. Auf diese Weise können Sie sicherstellen, dass sich Ihre Klassen auf ihre einzige Verantwortung konzentrieren, und es ist weniger wahrscheinlich, dass Sie vorhandenen Code ändern müssen, der nicht in Beziehung steht.

kiwicomb123
quelle