Ich habe eine Java-Klasse, die benutzerdefinierte Java-Ereignisse auslöst. Die Struktur des Codes ist wie folgt:
%Vor%Alles funktioniert korrekt, aber ich möchte eine neue Unterklasse von A erstellen (nennen Sie es B), die ein neues Ereignis auslösen kann. Ich denke an die folgende Änderung:
%Vor%Ist das der richtige Ansatz? Ich habe im Internet nach Beispielen gesucht, konnte aber keine finden.
Es gibt ein paar Dinge, die ich in dieser Lösung nicht mag:
BListener
hat zwei Methoden, die AEvent
verwenden, die andere BEvent
als Parameter. B
class hat beide Methoden addAListener
und addBListener
. Soll ich addAListener mit einem privaten Schlüsselwort ausblenden? [UPDATE: Es ist nicht möglich, mit einem privaten Schlüsselwort zu verbergen]
fireAListenerEvent1
und fireBListenerEvent1
Methoden. Ich benutze Java Version 1.5.
Ich sehe keinen Grund, warum BListener
AListener
erweitern sollte.
Möchten Sie wirklich alle an B
-Ereignissen Interessierten dazu bringen, auch event1()
zu implementieren?
Sie können auch addAListener()
nicht hinzufügen, da eine abgeleitete Klasse die Sichtbarkeit einer Methode, die in der Elternklasse vorhanden ist, nicht verringern kann. Außerdem sollten Sie das Liskov-Substitutionsprinzip nicht verletzen oder verletzen (jedes B muss alles können) ein A kann tun).
Und als letzte Bemerkung würde ich die fire*()
Methoden schützen. Es gibt normalerweise keinen Grund, sie öffentlich zu machen, und die Anzahl der öffentlichen Mitglieder zu reduzieren, hält Ihre öffentliche Schnittstelle sauber.
Verwende keine Erbschaft, es ist nicht das, was du willst und es wird zu einem spröden und schwer zu ändernden Design führen. Die Komposition ist ein flexiblerer und besserer Ansatz für das Design. Versuchen Sie immer, Interfaces so granular wie möglich zu gestalten, da sie nicht geändert werden sollten. Sie sind Ihr Vertrag mit dem Rest des Systems. Wenn neue Funktionen hinzugefügt werden müssen, besteht die erste Möglichkeit darin, dem Ereignis weitere Informationen hinzuzufügen. Wenn das nicht angemessen ist, sollten Sie eine neue Schnittstelle für die Übermittlung dieses Ereignisses entwerfen. Dies verhindert, dass existierender Code geändert werden muss, der nicht betroffen ist.
Hier ist mein Lieblingsmuster dafür, ich glaube, es wird allgemein als Beobachter bezeichnet.
Erstellen Sie eine neue Schnittstelle, die Methoden für diesen Ereignistyp definiert (fooEvent () addFooEventListener () removeFooEventListener ()). Implementieren Sie diese Schnittstelle in der konkreten Klasse, die diese Ereignisse generiert. (Ich nenne das normalerweise so etwas wie SourcesFooEvent, FiresFooEvent, FooEventSource, usw.)
Wenn Sie die Code-Duplizierung reduzieren möchten, können Sie eine Hilfsklasse erstellen, die die Registrierung der Listener behandelt, sie in einer Sammlung speichert und eine Fire-Methode für die Veröffentlichung der Ereignisse bereitstellt.
Generika können hier helfen. Zuerst eine generische Listener-Schnittstelle:
%Vor%Als nächstes eine passende EventSource-Schnittstelle:
%Vor%Endlich eine abstrakte Basisklasse, um schnell eine Hilfsklasse für die Registrierung von Listenern und die Ereignisverteilung zu erstellen:
%Vor%Sie würden den abstrakten EventDispatcher durch Kapselung verwenden, so dass jede andere Klasse EventSource einfach implementieren kann, ohne dass sie eine bestimmte Klasse erweitern muss.
%Vor%Dies zeigt hoffentlich das gute Gleichgewicht zwischen Typensicherheit (wichtig), Flexibilität und Wiederverwendung von Code.
Ich verstehe von deinem Kommentar zu saga, dass das feuern von B automatisch A feuern wird.
Warum nicht einen einzelnen Typ von Listener verwenden und dann einige Vererbung, Delegation und Generika mischen?
%Vor%Erläuterung: Der Code zum Verwalten von Listenern ist im Listener-Manager der Basisklasse freigegeben. B kann nur aufgrund der generischen Kompilierzeitprüfung BListener empfangen. Feuern B wird automatisch A auslösen.
Es scheint mir, dass Sie die Dinge sehr einfach halten können.
Mein understading
Sie haben eine Basisklasse A , die einige basicOperation
Sie haben möglicherweise eine spezifischere Unterklasse B , die außerdem einige specificOperations
Wenn das der Fall ist, müssen Sie beide Ereignisse behandeln ( basic für A und basic + spezifisch für B)
Nun, Sie müssen die Methoden nicht überladen, um dies zu tun. Sie müssen nur bestimmte Handler (oder Listener) für bestimmte Ereignisse hinzufügen.
Es kann der Fall sein, dass das Ereignis "grundlegend" ist, das ist in Ordnung.
Aber wenn das Ereignis spezifisch ist, müssen Sie entsprechend reagieren. Also, was ich tun würde, ist ein Check in dem spezifischen Listener hinzuzufügen, um das spezifische Ereignis wie folgt zu unterscheiden:
%Vor%Und das ist es.
Ihre Beschreibung des Problems ist zu abstrakt, daher können keine konkreten Lösungen vorgeschlagen werden. Aber wenn es schwierig ist zu erklären, was Sie erreichen möchten, müssten Sie wahrscheinlich zuerst analysieren, was das Problem an erster Stelle ist.
Wenn mein oben stehendes Verständnis korrekt ist (Sie müssen basic + spezifisch einige Male handhaben), kann der folgende lange Code hilfreich sein.
Mit freundlichen Grüßen
%Vor%Beispielausgabe:
%Vor%Wenn Sie weiter gehen, können Sie sogar die Schnittstellen loswerden, um es einfacher zu halten
Wenn
%Vor%können Sie nicht etwas wie:
%Vor%Wie ich im Kommentar gesagt habe, bin ich mir nicht sicher, was Sie eigentlich erreichen wollen? Wer wird von wo aus angerufen, und was muss er tun, wenn er angerufen wird?
Basierend auf den wenigen Informationen, die wir über die Beziehung zwischen A
& amp; B
, ich denke, es ist verwirrend, BListener
zu einer Subschnittstelle von AListener
zu machen. Wie der Name schon sagt, sollte BListener
auf BEvent
s warten, die bereits eine Unterklasse von AEvent
s sind. Aus Gründen der Klarheit sollten Zuhörer anspruchsvolle Zwecke haben; Sie sollten sich nicht unnötig überlappen. Außerdem sind solche überlappenden Listener nicht notwendig, da Sie bereits separate Methoden in der Klasse B
definieren, um verschiedene Arten von Listenern zu behandeln.
Um diesen Punkt zu verdeutlichen, betrachten Sie dieses Beispiel nach Ihrem Code:
%Vor% Dieses Design funktioniert, ist aber verwirrend, weil ClickableMouseListener
zwei Arten von Ereignissen behandelt und ClickableMouseWidget
zwei Arten von Listenern behandelt, wie Sie richtig angemerkt haben. Betrachten Sie nun die folgende Alternative, die Komposition statt Vererbung verwendet:
Tags und Links java inheritance events listener