Warum verwendet ShapeFactory bedingte Anweisungen, um zu bestimmen, welches Objekt instanziiert werden soll. Müssen wir ShapeFactory nicht ändern, wenn wir in Zukunft weitere Klassen hinzufügen möchten? Warum verstößt dies nicht gegen das Open-Closed-Prinzip?
design
design-patterns
factory-method
factory
Armon Safai
quelle
quelle
Antworten:
Die konventionelle objektorientierte Weisheit besteht darin,
if
Anweisungen zu vermeiden und sie durch den dynamischen Versand überschriebener Methoden in Unterklassen einer abstrakten Klasse zu ersetzen. So weit, ist es gut.Der Sinn des Factory-Musters besteht jedoch darin , dass Sie nicht mehr über die einzelnen Unterklassen Bescheid wissen müssen und nur noch mit der abstrakten Oberklasse arbeiten müssen . Die Idee ist, dass die Factory besser als Sie weiß, welche bestimmte Klasse instanziiert werden soll, und dass Sie nur mit den Methoden arbeiten sollten, die von der Superklasse veröffentlicht wurden. Dies ist oft wahr und ein wertvolles Muster.
Daher kann das Schreiben einer Factory-Klasse auf keinen Fall auf die
if
Anweisungen verzichten . Es würde die Last der Auswahl einer bestimmten Klasse auf den Anrufer verlagern, genau das soll das Muster vermeiden. Nicht alle Prinzipien sind absolut (in der Tat ist kein Prinzip absolut), und wenn Sie dieses Muster verwenden, gehen Sie davon aus, dass der Nutzen davon größer ist als der Nutzen, wenn Sie kein verwendenif
.quelle
if
s zu erstellen . In der Antwort von @ BЈовић finden Sie ein einfaches Beispiel, wie dies erreicht werden kann. Abgestimmt.Im Beispiel wird wahrscheinlich eine bedingte Anweisung verwendet, da dies die einfachste ist. Eine komplexere Implementierung könnte eine Map oder Konfiguration oder (wenn Sie wirklich ausgefallen sein möchten) eine Art Registrierung verwenden, in der sich die Klassen selbst registrieren können. Es ist jedoch nichts Falsches daran, eine Bedingung zu verwenden, wenn die Anzahl der Klassen gering ist und sich selten ändert.
Die Ausweitung der Bedingung auf die Unterstützung einer neuen Unterklasse in der Zukunft wäre in der Tat eine Verletzung des offenen / geschlossenen Prinzips. Die "richtige" Lösung wäre, eine neue Fabrik mit der gleichen Schnittstelle zu erstellen. Die Einhaltung des O / C-Prinzips sollte jedoch immer gegen andere Designprinzipien wie KISS und YAGNI abgewogen werden.
Der angezeigte Code ist jedoch eindeutig ein Beispielcode, der das Konzept einer Fabrik und nichts anderes darstellen soll. ZB ist es ein schlechter Stil, wie im Beispiel null zurückzugeben, aber eine aufwändigere Fehlerbehandlung würde den Punkt nur verdunkeln. Der Beispielcode ist kein Code für die Produktionsqualität.
quelle
Das Muster selbst verstößt nicht gegen das Open / Closed-Prinzip (OCP). Wir verletzen jedoch die OCP, wenn wir das Muster falsch verwenden.
Die einfache Antwort auf diese Frage lautet wie folgt:
In dem bereitgestellten Beispiel unterstützt Ihre Basisfunktionalität drei Formen: Kreis, Rechteck und Quadrat. Angenommen, Sie müssen Triangle, Pentagon und Hexagon in Zukunft unterstützen. Um dies OHNE Verletzung von OCP zu tun , müssen Sie eine zusätzliche Factory erstellen, um Ihre neuen Shapes zu unterstützen (wir rufen sie auf
AdvancedShapeFactory
), und dann mit AbstractFactory entscheiden, welche Factory Sie erstellen müssen, um welche Shapes Sie benötigen.quelle
Wenn Sie über das Abstract Factory-Muster sprechen, liegt die Entscheidungsfindung häufig nicht in der Factory selbst, sondern im Anwendungscode. Dieser Code wählt aus, welche konkrete Factory instanziiert und an den Clientcode übergeben werden soll, der von der Factory erzeugte Objekte verwendet. Das Ende des Java-Beispiels finden Sie hier: https://en.wikipedia.org/wiki/Abstract_factory_pattern
Entscheidungsfindung impliziert nicht unbedingt
if
Aussagen. Es könnte den konkreten Factory-Typ aus einer Konfigurationsdatei lesen, ihn aus einer Kartenstruktur ableiten usw.quelle
Wenn Sie über das Öffnen-Schließen auf Klassenebene mit dieser Factory nachdenken, erstellen Sie eine andere Klasse in Ihrem System. Öffnen-Schließen. Wenn Sie beispielsweise eine andere Klasse haben, die eine Form annimmt und die Fläche berechnet (typisches Beispiel), ist diese Klasse OpenClose, weil Es kann die Fläche für neue Arten von Formen ohne Änderung berechnen. Dann haben Sie eine andere Klasse, die die Form zeichnet, eine andere Klasse, die N Formen annimmt und die größere zurückgibt, und Sie können allgemein annehmen, dass die anderen Klassen in Ihrem System, die sich mit Formen befassen, Open-Close sind (zumindest über Formen). In Bezug auf das Design ermöglicht die Fabrik, dass der Rest des Systems offen und geschlossen ist, und die Fabrik selbst ist NICHT offen und geschlossen.
Natürlich können Sie diese Fabrik auch durch eine Art dynamisches Laden auf- und zuklappen lassen und Ihr gesamtes System kann auf- und zuklappen (Sie können beispielsweise neue Formen hinzufügen, indem Sie ein Glas in den Klassenpfad legen). Sie müssen bewerten, ob sich diese zusätzliche Komplexität je nach dem System lohnt, das Sie erstellen. Nicht alle Systeme benötigen steckbare Funktionen und nicht alle Systeme müssen vollständig geöffnet und geschlossen sein.
quelle
Das Open-Closed-Prinzip gilt als Liskov-Substitutionsprinzip für Klassenbäume und Vererbungshierarchien. In Ihrem Beispiel befindet sich die Factory-Klasse nicht im Stammbaum der Klassen, die sie instanziiert, sodass diese Regeln nicht verletzt werden können. Es würde eine Verletzung geben, wenn Ihr GetShape (oder besser CreateShape) in der Shape-Basisklasse implementiert würde.
quelle
Es hängt alles davon ab, wie Sie es implementieren. Mit können Sie
std::map
Funktionszeiger auf Funktionen speichern, die Objekte erstellen. Dann wird das Auf / Zu-Prinzip nicht verletzt. Oder Schalter / Koffer.Auf jeden Fall können Sie die Abhängigkeitsinjektion immer verwenden, wenn Ihnen das Factory-Muster nicht gefällt.
quelle