Erweiterung der parametrisierten Factory-Methode in Java

8

Ich bin neu in OOP und lerne Designmuster, also schrieb ich einen einfachen Code, um eine Factory-Methode auszuprobieren, und alles scheint gut, außer wenn ich einen anderen Subtyp hinzufügen möchte. Hier ist der Code soweit:

%Vor%

Wenn die Anforderung später geändert wird, um eine Unterklasse Pensioner einzufügen, wenn das Alter & gt; 70, ich müsste entweder:

Fügen Sie der if (age > 70) return new Pensioner(); -Methode in der Klasse create() die Zeile PersonFactory hinzu, die das Open-Closed-Prinzip sicher unterbricht? Oder, wie im Buch The Gang Of Four Design Patterns vorgeschlagen, überschreiben Sie die parametrisierte Factory-Methode, um die Produkte, die ein Creator erzeugt, selektiv zu erweitern. In diesem Fall würde das wohl bedeuten, eine neue Klasse zu schreiben:

%Vor%

Das bedeutet nun, dass entweder alle Clients, die PersonFactory aufrufen, geändert werden müssen, um stattdessen PersonFactoryWithPensioner zu verwenden, oder ich muss akzeptieren, dass neue Clients PersonFactoryWithPensioner aufrufen können, während die alten Clients z. ClientA würde immer noch nur ein Adult -Objekt erhalten, wenn das Alter & gt; 70. Es wird noch schlimmer, wenn später eine andere Unterklasse, z. Infant wird hinzugefügt. Um sicherzustellen, dass die neuen Kunden das Objekt Infant , Child , Adult oder Pensioner erhalten, muss eine neue Klasse PersonFactoryWithInfant PersonFactoryWithPensioner erweitern. Das kann nicht richtig sein, scheint eher missverstanden zu haben, was GoF vorschlägt.

Meine Frage ist: Gibt es eine Möglichkeit, einen neuen Untertyp hinzuzufügen, der an alte Clients zurückgegeben werden kann, ohne sie zu ändern, und ohne den OCP zu ändern, indem der PersonFactory -Code so geändert wird, dass er den neuen Untertyp enthält?

Entschuldigung, wenn ich das nicht richtig gepostet habe, stelle ich hier zum ersten Mal eine Frage. Ich habe vorangegangene Antworten für ähnliche Probleme durchgesehen, aber sie scheinen sich damit nicht zu befassen.

    
Andy Tipp 20.01.2017, 16:26
quelle

5 Antworten

2

Ich denke, OCP hört nicht damit auf, irgendeine Methode oder Klasse zu modifizieren.

Aber es schlägt vor, dass Sie, wenn Sie Änderungen vornehmen müssen, dies tun sollten, damit Sie diesen Code nicht noch einmal ändern müssen.

Da Sie möglicherweise später PersonFactory ändern müssen, können Sie eine weitere Klasse Factory erstellen, um Objekte vom Typ PersonFactory zu erstellen. Obwohl dies wie überentwickelte Lösung aussieht.

Eine andere mögliche Lösung wäre, dass PersonFactory diese Regeln aus einer dynamischen Quelle lädt, zum Beispiel diese Regeln in einer Datei mit dem JSON-Format speichert. Und dann Objekte dynamisch mit Reflektion erstellen.

In etwa so:

%Vor%

Die json-Regeln würden etwa so aussehen:

%Vor%

Auf diese Weise brechen Sie das OCP-Prinzip nicht.

    
alayor 20.01.2017 16:54
quelle
2

Das Prinzip "offen-geschlossen" ist gut zu beachten. Es funktioniert jedoch nicht gut mit Fabriken. Eine Option dieser Art von Arbeiten ist die folgende, die die Fabrik in eine Registrierung verwandelt:

%Vor%

Ähnlich wie @alayor die Antwort, der einzige Weg, um zu vermeiden, die Logik der Fabrik zu ändern, oder die Fabrik komplett austauschen zu müssen und alle dazu zu bringen, die neue Version zu benutzen ... ist für die Fabrik, um ihre Logik von woanders zu bekommen. @alayor ruft es aus einer Konfigurationsdatei ab; Ich schlage vor, es als Teil seiner Initialisierung der Fabrik hinzuzufügen (könnte auch im Fabrikkonstruktor gemacht werden; ändern Sie es zum Beispiel in public PersonFactory(PersonCreator ... rules) ).

Vollständiger Code:

%Vor%     
tucuxi 20.01.2017 17:43
quelle
2

Regeln sind manchmal dazu gedacht, gebrochen zu werden, also sage ich BREAK das Geschlossene Prinzip, um es sauber und einfach zu halten. Der Mehraufwand beim Erstellen mehrerer Factory-Klassen für jede Art von Person bricht meiner Meinung nach den gesamten Zweck der Factory-Methode. Wenn Sie das Closed-Prinzip umgehen, können Sie eine einzelne -Klasse zum Erstellen eines beliebigen Personentyps erstellen.

%Vor%     
RAZ_Muh_Taz 20.01.2017 16:52
quelle
1

Die Frage ist "Erwarten Sie, dass ein Rentner-Objekt ohne Code-Änderung erstellt wird?". Wenn ja, dann sollten Sie die "Closed" -Regel brechen und den Werkscode aktualisieren. Wenn nicht, sollten Sie eine neue Factory erstellen und die Clients verwenden sie.

    
jaudo 20.01.2017 16:51
quelle
1

Alle Antworten hier, die darauf hindeuten, dass eine Art von dynamischen Regeln das Prinzip des Aufbrechens / Schließens aufbrechen. Bei diesem Prinzip geht es nicht darum, "einen Code, der bereits geschrieben wurde, nicht zu ändern", sondern "das Ergebnis eines bereits verwendeten Codes nicht zu ändern". Das heißt, wenn ein Client erwartet, dass er nur zwei Ergebnisse erhalten kann - Adult oder Child, die dritte Möglichkeit entweder durch Festcodierung in Funktion oder durch dynamische Regelsätze bietet, bricht das Open-Close-Prinzip.

Aber zurück zu Ihrer Frage - ich werde sagen, es kommt darauf an. Prinzipien und Muster sind nett, lustig und alles andere als in der realen täglichen Arbeit muss man immer auf das große Bild schauen und entscheiden, ob man bestimmte Regeln anwendet oder nicht. Behandle sie als Andeutungen, nicht als etwas, das in Stein geschrieben ist.

Wenn Ihr Code etwas geschlossen ist, haben Sie die Kontrolle über jeden Aufruf von PersonFactory, dann sind Änderungen im Lebenszyklus Ihrer Software eine normale Sache. Ich erinnere mich nicht an ein echtes Lebensprojekt, an dem ich teilgenommen habe und das keinen Code verändert hat, der zuvor erstellt wurde. Tatsächlich machen wir es täglich:)

Eine andere Sache ist, wenn Ihr Code von einer unbekannten Anzahl von Clients von Drittanbietern verwendet wird (z. B. öffentliche API). Dann sollten Sie vorsichtig sein, um etwas nicht zu brechen, aber auch neue Logik in bestehenden Methoden zu präsentieren (wie hier, wenn Sie ein neues Konzept von Person hinzufügen) ist vollkommen akzeptabel. Wenn diese Änderungen brechen würden, dann erwägen Sie, eine neue / aktualisierte Version des geänderten Codes neben der alten hinzuzufügen (und möglicherweise einen Plan der alten Version irgendwann in der Zukunft zu verwerfen, da Sie wirklich nicht 10000 Versionen Ihres Codes pflegen wollen; )

Denken Sie auch an andere OOP-Teile, die Ihnen helfen sollten, einige Probleme zu vermeiden. In Ihrem Beispiel implementiert Adult, Child und Rentner Person Interface, was großartig ist. Jeder Code, der nur Adult- und Child-Implementierungen kennt, sollte kein Problem mit dem Rentner-Wert haben, da alle nur Personalimplementierungen sind und dieser Code Rentner auch als Person behandeln sollte, ohne zu wissen, dass Sie einen neuen Typ eingeführt haben.

    
Vir 20.01.2017 20:58
quelle