Entwurfsmuster: Factory vs Factory-Methode vs Abstract Factory

183

Ich habe Designmuster von einer Website gelesen

Dort habe ich über Factory, Factory-Methode und Abstract Factory gelesen, aber sie sind so verwirrend, dass die Definition nicht klar ist. Nach Definitionen

Factory - Erstellt Objekte, ohne die Instanziierungslogik dem Client zur Verfügung zu stellen, und verweist über eine gemeinsame Schnittstelle auf das neu erstellte Objekt. Ist eine vereinfachte Version der Factory-Methode

Factory-Methode - Definiert eine Schnittstelle zum Erstellen von Objekten, lässt jedoch Unterklassen entscheiden, welche Klasse instanziiert werden soll, und verweist über eine gemeinsame Schnittstelle auf das neu erstellte Objekt.

Abstract Factory - Bietet die Schnittstelle zum Erstellen einer Familie verwandter Objekte, ohne deren Klassen explizit anzugeben.

Ich habe mir auch die anderen Stackoverflow-Threads in Bezug auf Abstract Factory vs Factory Method angesehen, aber die dort gezeichneten UML-Diagramme machen mein Verständnis noch schlimmer.

Kann mir bitte jemand sagen

  1. Wie unterscheiden sich diese drei Muster voneinander?
  2. Wann welche verwenden?
  3. Und wenn möglich auch Java-Beispiele zu diesen Mustern?
Just_another_developer
quelle
3
Während ich nach Antworten auf ungefähr die gleiche Frage wie das OP suchte, fand ich diesen Artikel: Von keiner Fabrik zur Fabrikmethode . Es liefert den Einblick, indem es die Entwicklung eines Beispielprojekts verfolgt (die im Titel erwähnte Fabrikmethode ist einer der Evolutionsschritte).
Nick Alexeev

Antworten:

250

Alle drei Factory-Typen machen dasselbe: Sie sind ein "intelligenter Konstruktor".

Angenommen, Sie möchten zwei Obstsorten herstellen können: Apfel und Orange.

Fabrik

Factory ist "behoben", da Sie nur eine Implementierung ohne Unterklasse haben. In diesem Fall haben Sie eine Klasse wie diese:

class FruitFactory {

  public Apple makeApple() {
    // Code for creating an Apple here.
  }

  public Orange makeOrange() {
    // Code for creating an orange here.
  }

}

Anwendungsfall: Das Konstruieren eines Apple oder eines Orange ist etwas zu komplex, um es im Konstruktor zu verarbeiten.

Fabrikmethode

Die Factory-Methode wird im Allgemeinen verwendet, wenn Sie eine generische Verarbeitung in einer Klasse haben, aber variieren möchten, welche Art von Obst Sie tatsächlich verwenden. So:

abstract class FruitPicker {

  protected abstract Fruit makeFruit();

  public void pickFruit() {
    private final Fruit f = makeFruit(); // The fruit we will work on..
    <bla bla bla>
  }
}

... dann können Sie die allgemeine Funktionalität in wiederverwenden, FruitPicker.pickFruit()indem Sie eine Factory-Methode in Unterklassen implementieren:

class OrangePicker extends FruitPicker {

  @Override
  protected Fruit makeFruit() {
    return new Orange();
  }
}

Abstrakte Fabrik

Abstract Factory wird normalerweise für Dinge wie Abhängigkeitsinjektion / -strategie verwendet, wenn Sie in der Lage sein möchten, eine ganze Familie von Objekten zu erstellen, die "der gleichen Art" sein müssen und einige gemeinsame Basisklassen haben. Hier ist ein vage fruchtbezogenes Beispiel. Der Anwendungsfall hier ist, dass wir sicherstellen möchten, dass wir nicht versehentlich einen OrangePicker auf einem Apple verwenden. Solange wir unsere Obst- und Pflücker aus derselben Fabrik beziehen, werden sie zusammenpassen.

interface PlantFactory {

  Plant makePlant();

  Picker makePicker(); 

}

public class AppleFactory implements PlantFactory {
  Plant makePlant() {
    return new Apple();
  }

  Picker makePicker() {
    return new ApplePicker();
  }
}

public class OrangeFactory implements PlantFactory {
  Plant makePlant() {
    return new Orange();
  }

  Picker makePicker() {
    return new OrangePicker();
  }
}
Anders Johansen
quelle
8
+1 Dies ist die Antwort, die meinem Verständnis dieser Muster am ähnlichsten ist. Das Hinzufügen von Beispielen für das Aufrufen von Code (Client) würde ebenfalls helfen? Die Frage, die mich sehr stört, ist: Können wir sagen, dass das abstrakte Factory-Muster nur mit dem Factory-Methodenmuster ab Werk erweitert wurde (wenn dies zutrifft, bin ich zu diesem Thema klar)?
Croraf
9
Dies ist das Beispiel, nach dem ich jahrelang gesucht habe.
Taztingo
Das ist eine fantastische Erklärung! Vielen Dank!
André Andrade
@ AndréAndrade Wie rufe ich die Factory-Methode auf ? Ein kleiner Code samle pls :) Das wird meine Zweifel an seiner Verwendung
klären
25
  1. Wie unterscheiden sich diese drei Muster voneinander?

Factory: Erstellt Objekte, ohne die Instanziierungslogik dem Client zur Verfügung zu stellen.

Factory-Methode: Definieren Sie eine Schnittstelle zum Erstellen eines Objekts, lassen Sie jedoch die Unterklassen entscheiden, welche Klasse instanziiert werden soll. Mit der Factory-Methode kann eine Klasse die Instanziierung auf Unterklassen verschieben

Abstract Factory: Bietet eine Schnittstelle zum Erstellen von Familien verwandter oder abhängiger Objekte, ohne deren konkrete Klassen anzugeben.

Das AbstractFactory- Muster verwendet die Komposition, um die Verantwortung für das Erstellen eines Objekts an eine andere Klasse zu delegieren, während das Entwurfsmuster der Factory-Methode die Vererbung verwendet und zum Erstellen des Objekts auf abgeleiteten Klassen oder Unterklassen basiert

  1. Wann welche verwenden?

Factory: Der Kunde benötigt nur eine Klasse und kümmert sich nicht darum, welche konkrete Implementierung er erhält.

Factory-Methode: Der Client weiß nicht, welche konkreten Klassen zur Laufzeit erstellt werden müssen, sondern möchte nur eine Klasse erhalten, die die Aufgabe übernimmt.

AbstactFactory: Wenn Ihr System mehrere Produktfamilien erstellen muss oder Sie eine Produktbibliothek bereitstellen möchten, ohne die Implementierungsdetails offenzulegen.

Abstract Factory-Klassen werden häufig mit der Factory-Methode implementiert. Factory-Methoden werden normalerweise in Template-Methoden aufgerufen.

  1. Und wenn möglich auch Java-Beispiele zu diesen Mustern?

Factory und FactoryMethod

Absicht:

Definieren Sie eine Schnittstelle zum Erstellen eines Objekts, lassen Sie jedoch Unterklassen entscheiden, welche Klasse instanziiert werden soll. Mit der Factory-Methode kann eine Klasse die Instanziierung auf Unterklassen verschieben.

UML-Diagramm :

Geben Sie hier die Bildbeschreibung ein

Produkt: Definiert eine Schnittstelle der Objekte, die die Factory-Methode erstellt.

ConcreteProduct: Implementiert die Produktschnittstelle

Ersteller: Deklariert die Factory-Methode

ConcreateCreator: Implementiert die Factory-Methode, um eine Instanz eines ConcreteProduct zurückzugeben

Problemstellung: Erstellen Sie eine Factory of Games mithilfe von Factory-Methoden, die die Spieloberfläche definieren.

Code-Auszug:

Fabrikmuster. Wann werden Werksmethoden angewendet?

Vergleich mit anderen Schöpfungsmustern:

  1. Das Design beginnt mit der Factory-Methode (weniger kompliziert, anpassbarer, Unterklassen vermehren sich) und entwickelt sich zu Abstract Factory, Prototype oder Builder (flexibler, komplexer), wenn der Designer feststellt, wo mehr Flexibilität erforderlich ist

  2. Abstract Factory- Klassen werden häufig mit Factory-Methoden implementiert , können jedoch auch mit Prototype implementiert werden

Referenzen zur weiteren Lektüre: Sourcemaking Design-Patterns

Ravindra Babu
quelle
Sollte es für die Factory-Methode nicht eine Oberklasse definieren?
Tony Lin
20

Factory - Separate Factory-Klasse zum Erstellen komplexer Objekte.

Beispiel: FruitFactory-Klasse zum Erstellen eines Objekts von Fruit

class FruitFactory{

public static Fruit getFruit(){...}

}

Factory-Methode - Fügen Sie anstelle einer vollständigen separaten Klasse für die Factory nur eine Methode in dieser Klasse selbst als Factory hinzu.

Ex:

Calendar.getInstance() (Java's Calendar)

Abstrakte Fabrikmethode - Fabrik der Fabrik

Beispiel: Nehmen wir an, wir wollen eine Fabrik für Computerteile bauen. Es gibt also verschiedene Arten von Computern wie Laptop, Desktop, Server.

Für jeden Computertyp benötigen wir also eine Fabrik. Also schaffen wir eine Fabrik auf hoher Ebene mit Fabriken wie unten

ComputerTypeAbstractFactory.getComputerPartFactory(String computerType) ---> This will return PartFactory which can be one of these ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Jetzt sind diese 3 selbst wieder Fabriken. (Sie werden sich mit PartFactory selbst befassen, aber unter der Haube wird es eine separate Implementierung geben, die auf dem basiert, was Sie in der abstrakten Factory bereitgestellt haben.)

  Interface-> PartFactory. getComputerPart(String s), 
Implementations -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Usage:
new ComputerTypeAbstractFactory().getFactory(“Laptop”).getComputerPart(“RAM”)

BEARBEITEN: bearbeitet, um genaue Schnittstellen für Abstract Factory gemäß den Einwänden in den Kommentaren bereitzustellen.

Ravi K.
quelle
1
Die Idee dahinter ComputerFactorywäre, dass Sie eine gemeinsame Erstellungsoberfläche haben (getScreen(); getKeyboard(); getDiskdrive(); ... ) haben, keine Schnittstelle pro Computertyp, wie Sie vorschlagen. Sie können ein Designproblem riechen, wenn Sie dasselbe Wort zweimal in derselben Anweisung verwenden: Laptop Factory.get Laptop Part ().
xtofl
Nein, nein, nein, gehen Sie nicht genau auf den Code selbst ein. Es war nur eine Anologie zum Verständnis. Wenn Sie ein genaues Beispiel mit Schnittstellen wünschen, finden Sie es hier. Objekte: Schnittstelle -> ComputerPart, Implementierung -> RAM, Festplatte, Prozessor Factory: Schnittstelle-> PartFactory. getComputerPart (String s), Implementierungen -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory. Abstrakte Fabrik: ComputerType.getPartFactory ("String s") Verwendung: neuer ComputerType (). GetFactory ("Laptop"). GetComputerPart ("RAM")
Ravi K
2
Ich habe die Antwort aktualisiert, um mich um Ihr Anliegen zu kümmern. Eigentlich ist die abstrakte Fabrik nichts anderes als ein Fakt der Fabrik. Ich habe ein früheres Beispiel nur als Referenz angegeben (vorausgesetzt, die Leser kümmern sich während der tatsächlichen Implementierung um die Schnittstellen). Trotzdem danke für die Benachrichtigung. Es ist immer gut, sich zu verbessern. :) :)
Ravi K
Nein abstract Factoryist keine Fabrik der Fabrik ... Es ist ein abstract classoder ein interfacefähiges Objekt, das mit verschiedenen konkreten Fabriken implementiert / erweitert wird. Code-Details finden Sie in der akzeptierten Antwort. Und bitte entfernen oder bearbeiten Sie Ihre Antwort entsprechend.
Julien__
Ich mag die Erklärung der Fabrikmethode, die kurz genug ist, um zu enthüllen, warum sie so benannt ist. In diesem Muster ist die Factory die Methode, NICHT die Klasse, die im Allgemeinen kein Hilfsdienstprogramm ist, das Instanziierungsmethoden gruppiert, sondern für sich genommen von Bedeutung ist. Andere ausführlichere Antworten haben diesen Punkt leider verfehlt.
wlnirvana
11

Jedes Entwurfsmuster trägt dazu bei, dass geschriebener Arbeitscode nicht berührt wird. Wir alle wissen, dass es nach dem Berühren des Arbeitscodes Fehler in den vorhandenen Arbeitsabläufen gibt und dass noch viel mehr Tests durchgeführt werden müssen, um sicherzustellen, dass wir nichts kaputt machen.

Ein Factory-Muster erstellt Objekte basierend auf Eingabekriterien und stellt so sicher, dass Sie keinen Code schreiben müssen, wie dies der Fall ist. Erstellen Sie dann dieses Objekt oder dieses Objekt. Ein gutes Beispiel dafür ist eine Reise-Website. Eine Reise-Website kann nur Reisen (Flug, Zug, Bus) oder / und Hotels oder / und Touristenattraktionspakete anbieten. Wenn ein Benutzer als Nächstes auswählt, muss die Website entscheiden, welche Objekte erstellt werden sollen. Sollte es auch nur das Reise- oder Hotelobjekt erstellen.

Wenn Sie sich nun vorstellen, Ihrem Portfolio eine weitere Website hinzuzufügen, und Sie der Meinung sind, dass derselbe Kern verwendet wird, z. B. eine Fahrgemeinschaftswebsite, die jetzt nach Taxis sucht und online Zahlungen tätigt, können Sie eine abstrakte Fabrik in Ihrem Kern verwenden. Auf diese Weise können Sie einfach eine weitere Fabrik mit Kabinen und Fahrgemeinschaften einrasten lassen.

Beide Fabriken haben nichts miteinander zu tun, daher ist es ein gutes Design, sie in verschiedenen Fabriken zu halten.

Hoffe das ist jetzt klar. Studieren Sie die Website noch einmal unter Berücksichtigung dieses Beispiels, hoffentlich hilft es. Und ich hoffe wirklich, dass ich die Muster richtig dargestellt habe :).

Siddharth
quelle
3

Für diese Antwort verweise ich auf das Buch "Gang of Four".

Es gibt keine „Factory“ noch „Simple Factory“ noch „Virtual Factory“ Definitionen in dem Buch. Wenn Leute über das "Factory" -Muster sprechen, sprechen sie normalerweise über etwas, das ein bestimmtes Objekt einer Klasse erzeugt (aber nicht über das "Builder" -Muster). Sie können sich auf die Muster "Factory Method" oder "Abstract Factory" beziehen oder nicht . Jeder kann "Factory" implementieren, da dies kein formeller Begriff ist (denken Sie daran, dass einige Personen \ Unternehmen \ Communities ihren eigenen Wortschatz haben können).

Das Buch enthält nur Definitionen für "Abstract Factory" und "Factory Method".

Hier sind Definitionen aus dem Buch und eine kurze Erklärung, warum beide so verwirrend sein können. Ich lasse Codebeispiele weg, weil Sie sie in anderen Antworten finden können:

Factory-Methode (GOF) : Definieren Sie eine Schnittstelle zum Erstellen eines Objekts, lassen Sie jedoch die Unterklassen entscheiden, welche Klasse instanziiert werden soll. Mit der Factory-Methode kann eine Klasse die Instanziierung auf Unterklassen verschieben.

Abstract Factory (GOF) : Bieten Sie eine Schnittstelle zum Erstellen von Familien verwandter oder abhängiger Objekte, ohne deren konkrete Klassen anzugeben.

Quelle der Verwirrung : Oft kann man eine Klasse, die im Muster "Factory Method" verwendet wird, als "Factory" bezeichnen. Diese Klasse ist per Definition abstrakt. Deshalb ist es einfach, diese Klasse "Abstract Factory" zu nennen. Aber es ist nur der Name der Klasse; Sie sollten es nicht mit dem Muster "Abstract Factory" (Klassenname! = Mustername) verwechseln. Das Muster "Abstract Factory" ist anders - es wird keine abstrakte Klasse verwendet. Es definiert eine Schnittstelle (nicht unbedingt eine Programmiersprachenschnittstelle) zum Erstellen von Teilen eines größeren Objekts oder von Objekten, die miteinander in Beziehung stehen oder auf eine bestimmte Weise erstellt werden müssen.

Pavel Sapehin
quelle
2
AbstractProductA, A1 and A2 both implementing the AbstractProductA
AbstractProductB, B1 and B2 both implementing the AbstractProductB

interface Factory {
    AbstractProductA getProductA(); //Factory Method - generate A1/A2
}

Mit der Factory-Methode kann der Benutzer A1 oder A2 von AbstractProductA erstellen.

interface AbstractFactory {
    AbstractProductA getProductA(); //Factory Method
    AbstractProductB getProductB(); //Factory Method
}

Abstract Factory verfügt jedoch über mehr als eine Factory-Methode (z. B. 2 Factory-Methoden). Mit diesen Factory-Methoden wird die Menge der Objekte / verwandten Objekte erstellt. Mit Abstract Factory kann der Benutzer A1, B1-Objekte von AbstractProductA, AbstractProductB erstellen

rameshvanka
quelle
0

Niemand hat das ursprüngliche Buch Design Patterns: Elements of Reusable Object-Oriented Software zitiert , das die Antwort in den ersten beiden Absätzen des Abschnitts „Discussion of Creational Patterns“ (Schwerpunkt Mine) gibt:

Es gibt zwei gängige Methoden, um ein System anhand der von ihm erstellten Objektklassen zu parametrisieren. Eine Möglichkeit besteht darin, die Klasse, die die Objekte erstellt, in Unterklassen zu unterteilen . Dies entspricht der Verwendung des Factory-Methodenmusters (107). Der Hauptnachteil dieses Ansatzes besteht darin, dass eine neue Unterklasse erforderlich sein kann, um nur die Klasse des Produkts zu ändern. Solche Änderungen können kaskadieren. Wenn der Produktersteller beispielsweise selbst mit einer Factory-Methode erstellt wurde, müssen Sie auch den Ersteller überschreiben.

Der andere Weg , ein System zu parametrieren verlässt sich mehr auf Objekt Zusammensetzung : Definieren Sie ein Objekt , das für die Kenntnis der Klasse der Produktobjekte verantwortlich ist, und es ist ein Parameter des Systems machen. Dies ist ein Schlüsselaspekt der Muster Abstract Factory (87), Builder (97) und Prototype (117). Alle drei beinhalten das Erstellen eines neuen „Fabrikobjekts“, dessen Aufgabe es ist, Produktobjekte zu erstellen. Abstract Factory hat das Factory-Objekt, das Objekte mehrerer Klassen erzeugt. Builder lässt das Factory-Objekt ein komplexes Produkt schrittweise unter Verwendung eines entsprechend komplexen Protokolls erstellen. Beim Prototyp erstellt das Factory-Objekt ein Produkt, indem ein Prototyp-Objekt kopiert wird. In diesem Fall sind das Werksobjekt und der Prototyp dasselbe Objekt, da der Prototyp für die Rücksendung des Produkts verantwortlich ist.

Maggyero
quelle