Ich arbeite an einer GUI-Anwendung, die eine Konfigurationsdatei generiert. Ich habe eine Klassenhierarchie für das Konfigurationsmodell und verwende einen Objektbaum dieser Hierarchie in verschiedenen Kontexten. Derzeit verwende ich das Besuchermuster, um zu vermeiden, dass meine Modellklassen mit kontextspezifischem Code verschmutzt werden.
interface IConfigurationElement {
void acceptVisitor(IConfigurationElementVisitor visitor);
}
In einer früheren Version habe ich instanceof
anstelle des Besuchers Bedingungsketten verwendet. Beim Vergleich der beiden Ansätze sehe ich die folgenden Nachteile.
Besucher
- Es ist einfacher und sicherer, neue hinzuzufügen
IConfigurationElement
. Fügen Sie einfach eine neue Deklaration hinzuIConfigurationElementVisitor
und der Compiler generiert Fehler für alle Besucherimplementierungen. Beiinstanceof
Ketten müssen Sie sich alle Stellen merken, die Sie mit dem neuen Konfigurationselement erweitern müssen.instanceof
Verstößt grundsätzlich gegen das DRY-Prinzip, da es die Logik an mehreren Stellen dupliziert. - Das Besuchermuster ist effizienter als eine Kette von
instanceof
Bedingungen
Instanz von
- Der große Vorteil von
instanceof
ist seine Flexibilität. Soinstanceof
kann ich beispielsweise spezielle Lösungen für verschiedene Teilmengen vonIConfigurationElement
Implementierungen definieren, die in einigen Fällen ähnlich behandelt werden müssen. Im Gegensatz dazu zwingt mich Visitor, jedes Mal eine Methode für jede Implementierungsklasse zu implementieren.
Gibt es eine gemeinsame Lösung für diese Art von Problem? Kann ich den Besucher irgendwie anpassen, damit ich in einigen Fällen eine gemeinsame Lösung anbieten kann?
java
design-patterns
object-oriented-design
Johannes Luong
quelle
quelle
Antworten:
Sie können Besucher mit instanceOf verwenden
Schnittstellen:
Visitables:
Besucher:
Jede Klasse kennt nur die zugehörigen Schnittstellen. Wenn Sie also neue Besucher oder Besucher hinzufügen möchten, müssen Sie alles in dieser Kategorie (Besucher / Besucher) ändern (für Besucher muss nichts geändert werden, für Besucher muss eine neue Besucheroberfläche erstellt werden, aber nein Änderung bestehender Objekte).
Auf diese Weise gibt es keine Testinstanzkette, und Besucher für Teilmengen müssen nicht einmal über Typen außerhalb dieser Teilmenge Bescheid wissen.
Die Frage ist, was mit der Situation zu tun ist, in der A B erweitert (und B auch sichtbar ist). In diesem Fall könnten Sie einfach super.accept (Besucher) zu accept hinzufügen (es wäre also eine kurze Kette von Instanzen von s, aber nur als Solange die Hierarchie tief ist und nicht zu tief sein sollte, um eine Rolle zu spielen, müssen Sie sie nicht vollständig manuell schreiben.
quelle
IConfigurationElementVisitor
und nur nach bestimmten Besuchertypen zu suchenVisitable
. Obwohl dies eine mögliche Lösung ist, sehe ich einige Nachteile. Erstens würde dies die Stabilität des Besuchers beseitigen, über den ich gesprochen habe, und zweitens würde ich das Wissen über Besucher in meineVisitable
Implementierungen einbeziehen, was zu vermeiden ein Teil des Grundes war, Besucher überhaupt zu verwenden.Nun ja, du könntest. Erfassen Sie die Gemeinsamkeiten der vielen Konfigurationselemente, indem Sie ihnen Rollen zuweisen. Möglicherweise erhalten Sie eine Instanz von, jedoch nicht in einer Weise, die gegen das DRY-Prinzip verstößt, sondern um die statische Typisierung von Java zu umgehen.
Mit anderen Worten, Sie lassen den Besucher Konfigurationselemente generisch akzeptieren und über Rollen auf Gruppen von Implementierungen reagieren. Beachten Sie, dass Sie so spezifisch vorgehen können, wie Sie möchten, indem Sie Ihre Konfigurationselemente entsprechend modellieren.
Sie können hier das RoleInterface- Muster von Martin Fowler erkennen .
quelle
IConfigurationElement
, die speziell basierend auf der festgelegten Mitgliedschaft verarbeitet werden können. Sobald Sie Objekte mitinstanceof
Ihrem Compiler unterscheiden, kann Ihnen dies leider nicht weiterhelfen, wenn Sie vergessen, einen Ihrer Besucher zu aktualisieren. Ihre Lösung hat den Vorteil, dass alleinstanceof
Operatoren in einen gemeinsamen Typ eingebettet sind. Dies hilft, sie zu finden, indem Sie nach dem Typ suchen.accept
Methodensignaturen vermeiden . Zu diesem Zweck habe ich einen Catch-All-Ansatz vorgeschlagen, den Sie an Ihre Bedürfnisse anpassen können und der mehr oder weniger spezifisch für IhreIConfigurationElement
Implementierung ist. Zweitens wollten Sie die Flexibilität der Instanz von, vermutlich (im ersten Fall), weil Sie gemeinsame Merkmale in Ihren Implementierungsklassen haben - ansonsten kein Grund, dieaccept
Proliferation zunächst zu vermeiden . Dort habe ich vorgeschlagen,RoleInterface
wasinstanceof
anders verwendet wird.instanceof
:IConfigurationElement
Implementieren SieIRoleEnabled
und lassen Sie den Besucher jedes Konfigurationselement als rollenaktiviertes Element aufrufenvisitRoleEnabled
undvisitRoleEnabled
in jeder Implementierungsklasse den Besucher für jede der implementierten Rollen zurückrufen. Aber damit beginnen wir wild auf,instanceof
wenn es wirklich gut läuft.)Ich kann mir einige mögliche Lösungen vorstellen:
Erstellen Sie eine private Methode in der
Visitor
Implementierung und lassen Sie mehrerevisit
Methoden in derVisitor
Implementierung diese private Methode aufrufen.Wenn das oben Gesagte an vielen Stellen wiederholt wird, können Sie eine abstrakte Klasse erstellen
Visitor
, die eine Teilmenge vonvisit
Implementierungen implementiert und auf eine gemeinsameprotected abstract
Methode umleitet .Erstellen Sie mehrere
Visitor
Schnittstellen:Ich denke, 3 ist das, wonach Sie suchen. Es ist 100% statischer Polymorphismus und generiert Compiler-Warnungen, wenn ein Typ nicht behandelt wird. Der einzige Nachteil, den ich mir vorstellen kann, ist, dass die Wartung der
Visitable*
Implementierungen komplex werden kann, wenn viele verschiedeneVisitable*
Schnittstellen vorhanden sind.quelle