Meiner Meinung nach ist die von @TomDalling gegebene Antwort in der Tat richtig (was auch immer sie wert ist), aber es scheint immer noch eine Menge Verwirrung in den Kommentaren zu geben.
Ich habe hier einige leicht untypische Beispiele für die beiden Muster erstellt und versucht, sie auf den ersten Blick recht ähnlich erscheinen zu lassen. Dies wird helfen, die entscheidenden Unterschiede zwischen den beiden Mustern herauszuarbeiten.
Wenn Sie sich mit den Mustern noch nicht auskennen, sind diese Beispiele wahrscheinlich nicht der beste Startpunkt.
Fabrik-Methode
Client.javaish
Client(Creator creator) {
ProductA a = creator.createProductA();
}
Schöpfer.javaish
Creator() {}
void creatorStuff() {
ProductA a = createProductA();
a.doSomething();
ProductB b = createProductB();
b.doStuff();
}
abstract ProductA createProductA();
ProductB createProductB() {
return new ProductB1();
}
Warum gibt es eine Creator
und eine Client
?
Warum nicht? Die FactoryMethod
kann mit beiden verwendet werden, aber es wird der Typ von Creator
die das spezifische Produkt bestimmt.
Warum ist nicht createProductB
abstrakt in Creator
?
Eine Standardimplementierung kann bereitgestellt werden, Unterklassen können die Methode jedoch überschreiben, um ihre eigene Implementierung bereitzustellen.
Ich dachte, Fabrikmethoden erzeugen nur ein Produkt?
Jede Methode gibt nur ein Produkt zurück, aber der Ersteller kann mehrere Fabrikmethoden verwenden, die nicht notwendigerweise in irgendeiner Weise miteinander verbunden sind.
Abstrakte Fabrik
Client.javaish
AbstractFactory factory;
Client() {
if (MONDAY) {
factory = new Factory2();
} else {
factory = new AbstractFactory();
}
}
void clientStuff() {
ProductA a = factory.createProductA();
a.doSomething();
ProductB b = factory.createProductB();
b.doStuff();
}
Warte! Dein AbstractFactory
ist nicht, na ja... äh Abstrakt
Das ist okay, wir bieten immer noch eine Schnittstelle . Die Rückgabetypen für die Erstellungsmethoden sont Supertypen der Produkte, die wir herstellen wollen.
Heiliger Bimbam! Factory2
setzt nicht außer Kraft createProductA()
Was ist aus den "Produktfamilien" geworden?
Es gibt nichts im Muster, das besagt, dass ein Objekt nicht zu mehr als einer Familie gehören kann (auch wenn Ihr Anwendungsfall dies vielleicht nicht zulässt). Jede konkrete Fabrik ist dafür verantwortlich zu entscheiden, welche Produkte zusammen erstellt werden dürfen.
Das kann nicht richtig sein, die Client
verwendet keine Dependency Injection
Sie müssen entscheiden, was Ihre konkreten Klassen irgendwo sein werden, die Client
wird weiterhin in die AbstractFactory
Schnittstelle.
Die Verwirrung besteht darin, dass die Menschen Folgendes verwechseln Zusammensetzung con Dependency Injection . Die Client
HAS-A AbstractFactory
unabhängig davon, wie sie es bekommen hat. Im Gegensatz dazu steht die IS-A-Beziehung, Client
y AbstractFactory
keine Vererbung zwischen ihnen haben.
Wesentliche Unterschiede
- Bei Abstract Factory geht es immer um Familien von Objekten
- Factory Method ist nur eine Methode, die ermöglicht Unterklassen zur Angabe des Typs des konkreten Objekts
- Die abstrakte Factory bietet eine Schnittstelle zu einem Client und ist unabhängig davon, wo die Produkte verwendet werden. Die Factory-Methode kann vom Creator selbst verwendet oder einem Client zur Verfügung gestellt werden.
概要
El Zweck einer Fabrik ist die Bereitstellung eines Objekts, entweder für einen Kunden oder für sich selbst.
Ein Ersteller hat seine eigenen Verantwortlichkeiten und muss möglicherweise Objekte verwenden oder sie an einen Client weitergeben
Definieren Sie eine Schnittstelle für die Erstellung eines Objekts, aber lassen Sie die Unterklassen entscheiden, welche Klasse instanziert werden soll. Mit der Factory-Methode kann eine Klasse die Instanziierung auf Unterklassen verschieben. - GoF
Nur eine abstrakte Fabrik:
Bietet eine Schnittstelle zur Erstellung von Familien verwandter oder abhängiger Objekte, ohne dass deren konkrete Klassen angegeben werden müssen. - GoF
PlantUML-Code, wenn Sie mit den Diagrammen spielen wollen:
@startuml FactoryMethod
abstract class Creator {
creatorStuff()
{abstract} createProductA(): ProductA
createProductB(): ProductB
}
class Creator1 {
createProductA(): ProductA
}
class Creator2 {
createProductA(): ProductA
createProductB(): ProductB
}
together {
interface ProductA {
doSomething()
}
class ProductA1
' class Product1B
}
together {
interface ProductB {
doStuff()
}
class ProductB1
class ProductB2
}
Client --> Creator
Creator <|-- Creator1
Creator <|-- Creator2
Creator --> ProductB1
ProductA1 <-- Creator1
ProductA1 <-- Creator2
ProductB2 <-- Creator2
ProductA <|.. ProductA1
ProductB <|.. ProductB1
ProductB <|.. ProductB2
ProductA <- Creator
@enduml
@startuml AbstractFactory
together {
interface ProductA {
doSomething()
}
class ProductA1
}
together {
interface ProductB {
doStuff()
}
class ProductB1
class ProductB2
}
class AbstractFactory {
createProductA(): ProductA
createProductB(): ProductB
--
-
}
class Factory2 {
createProductB(): ProductB
}
Client --> AbstractFactory
AbstractFactory <|-- Factory2
ProductA <|.. ProductA1
ProductB <|.. ProductB1
ProductB <|.. ProductB2
AbstractFactory --> ProductA1
AbstractFactory --> ProductB1
ProductB2 <-- Factory2
@enduml