Ich habe eine, abstract class A
die eine abstrakte Methode deklariert doStuff
. Derzeit gibt es viele Klassen, die von erben A
und diese implementieren doStuff
.
Die Instanzen der Klasse werden zur Laufzeit über AFactory
basierend auf Benutzereingaben initialisiert . Ursprünglich hatten alle Klassen den gleichen Parameter (die Benutzereingabe). Aber jetzt habe ich einen zusätzlichen Parameter, den nur eine neue Klasse, die erbt, A
benötigt.
Also habe ich mir die folgende Logik überlegt:
Die Interpreter-Klasse, die Instanzen basierend auf Benutzereingaben generiert (
AFactory
natürlich unter Verwendung), kannte diesen zusätzlichen Parameter nicht.- Der Versuch, es in die Klasse der Klassendolmetscher zu schieben, wäre wirklich umständlich, denn dann müsste ich wissen, wann ich es an die Fabrik weitergeben muss, was den ganzen Zweck, überhaupt eine Fabrik zu haben, zunichte macht.
- Es blind in die Fabrik zu schicken, in der Hoffnung, dass es etwas damit anfangen könnte , scheint ebenfalls ziemlich hässlich.
Meine aktuelle Lösung: Inzwischen habe ich refactor beschlossen
A.doStuff(Param param)
inA.doStuff(AParams params)
.AParams
kann alle benötigten Parameter enthalten unddoStuff
kann sie dann ignorieren, wenn sie nicht an ihnen interessiert sind. Dies scheint mir auch etwas umständlich zu sein und verhindert, dass ich Strukturen in WIN32API sende, die viele hässliche nutzlose Parameter enthalten können, und ich mag es nicht.
Gibt es eine elegantere Möglichkeit, dieses Problem anzugehen? Oder ein Designmuster, das ich übersehen und gelöst habe?
Anmerkungen :
- Wir verwenden Java 1.7
- Die Namen der Klassen sind albern, um das theoretische Designproblem hervorzuheben. Sie haben in der Realität normale indikative, bedeutungsvolle Namen :)
- Ich habe die Suche ziemlich viel , aber habe herausgefunden, dass es ziemlich schwierig ist , das Web nach bestimmten abstrakten theoretischen Fragen zu suchen (im Gegensatz zu , warum
X
wirftException
in diesem Code) Ich habe beschlossen , auf jeden Fall zu fragen , so tut mir leid , wenn dies eine ist Duplikat.
Bearbeiten 1 :
- Klarstellung: Ich muss der
doStuff
Methode ein unterklassenspezifisches Argument übergeben .
EDIT 2 :
Ich habe die Absicht von Kilian Foth nicht vollständig verstanden, deshalb habe ich Java-Pseudocode geschrieben, um das Problem besser zu erklären / Ihre Lösung zu verstehen. Damit:
Dies ist ein Grundgerüst meines Problems.
Dies ist ein Grundgerüst meiner Lösung.
Dies ist meiner Meinung nach die Lösung von Kilian Foth, aber ich bin mir nicht sicher.
doStuff
Methode ein unterklassenspezifisches Argument übergeben müssen ?EntryPoint
Aufruf bekannt,main
der dann einige aufruft,Interpreter
die derzeit den zusätzlichen Parameter nicht als Parameter erhalten, ebenso wie die Factory. Der zusätzliche Parameter stammt von einer anderen Art von Benutzereingabe, die nicht von beschrieben wirdUserInput
(was ich leider nicht ändern kann).Antworten:
Der Sinn einer Fabrik besteht darin, die Tatsache zu verbergen, dass Sie möglicherweise Objekte aus leicht unterschiedlichen Klassen erhalten. Wenn einige dieser Objekte bestimmte Daten benötigen und andere nicht ...
Entweder sind sie nicht ähnlich genug, um von derselben Fabrik hergestellt zu werden. Dann müssen Sie mehr als eine Fabrik haben und die Entscheidung viel früher treffen als derzeit.
Oder sie sind ähnlich genug, dass es dem Kunden egal sein soll, welche er bekommt. Dann können Sie nicht erwarten, dass sich der Client darum kümmert, ob er die zusätzlichen Daten sendet oder nicht. Daraus folgt, dass sie immer übergeben werden müssen , aber die Factory ignoriert sie manchmal, ohne den Client mit diesen Implementierungsdetails zu belästigen. Alles andere würde den Kunden mit der Unterscheidung belasten, die die Fabrik verbergen sollte.
quelle
Ich gehe damit um, indem ich so etwas wie einen Builder verwende , der verschiedene Fabriken enthält. Der Builder erhält Hashes, die die Fabriken enthalten, um verschiedene Arten von Objekten zu erstellen. Er untersucht den Hash und ruft die richtige Factory basierend auf den Kriterien ab.
Zum Beispiel habe ich mehrere Fragetypen, und alle diese können durch eine Implementierung einer IQuestionFactory erstellt werden. Die meisten IQuestionFactory-Implementierungen sind Unterklassen von BaseQuestionFactory. Sie empfangen XML, das eine Frage darstellt, und analysieren es gemäß den Regeln der Frage, wobei einige Unterklassen von BaseQuestion zurückgegeben werden.
Einige Fragen benötigen weitere Informationen. Wenn es sich beispielsweise um eine Frage zum Ausfüllen von Formularen handelt, enthält möglicherweise ein Abschnitt des XML-Codes die Fragen, die die im Formular verwendeten Felder definieren. Die Fabriken, in denen diese Fragen gestellt werden, implementieren IEnhancedQuestionFactory, und der Builder überprüft die Factory, die er aus der QuestionFactoryRegistry abruft, und prüft, ob diese Schnittstelle implementiert ist. In diesem Fall wird das vollständige XML der Datei, die die Fragen enthielt, zusätzlich zu dem einzelnen XML übergeben, das an die Methode createQuestion gesendet wird.
Um Ihnen zu zeigen, wie flexibel dies sein kann, sind einige der IQuestionFactory-Implementierungen einfach Shells, die mehrere Fragenfabriken enthalten. Sie können das eingehende XML anzeigen und dann eine interne Factory aufrufen und alles zurückgeben, was dazu gehört. Wir verwenden dies, wenn eine XML-Datei mehrere Fragetypen enthält.
Es hört sich jedoch so an, als ob Sie eher die Art und Weise benötigen, wie wir Übungen erstellen (bei denen es sich im Wesentlichen um Controller handelt, die um eine Sammlung von Fragen gewickelt sind), bei denen der Hash (ExerciseFactoryMap) so eingerichtet ist, dass er die meiste Zeit eine Standardfactory zurückgibt, jedoch in bestimmten Fällen Wenn eine bestimmte Fabrik registriert ist, wird diese zurückgegeben. Und wir haben eine bestimmte Factory, die eine Übungsunterklasse mit einer zusätzlichen Eigenschaft erstellt und zusätzlich die Möglichkeit hat, das XML zu betrachten und die Informationen zu finden, die zum Auffüllen dieser Eigenschaft erforderlich sind.
Daher stimme ich Killian Foth zu, dass der Sinn einer Fabrik darin besteht, die Implementierungsdetails der Konstruktion des Objekts zu verbergen, aber nichts besagt, dass Sie nicht mehrere Fabriken auf kreative Weise kombinieren können (z. B. eine Fabrik) das enthält andere Fabriken, die die eigentliche Arbeit erledigen).
quelle
Der übliche Ansatz in solchen Fällen (Befehlsmuster) besteht darin, zusätzliche Parameter im Konstruktor zu übergeben. In Ihrem Fall, und fügen hinzu , dass die Mittel ,
otherArgument
umB
während der Bauphase.Das Umdrehen der Logik kann einige Optionen eröffnen. Zum Beispiel doStuff nach AParams verschieben:
Alternativ können Sie Ihren Stolz schlucken und mit
instanceof
in der Schleife überprüfen undotherArgument
manuell einstellen, bevor Sie anrufendoStuff
.Wenn dies nicht möglich ist, haben Sie keine andere Wahl, als das zu tun, was Sie tun (das Parameterargument erweitern). Analysieren Sie dieses Zeug nicht zu stark.
quelle