Ich habe eine vorhandene Codebase, die manchmal ArrayList oder LinkedList verwendet, und ich muss eine Möglichkeit finden, jedes Mal, wenn Hinzufügen oder Entfernen aufgerufen wird, zu protokollieren, was hinzugefügt oder entfernt wurde.
Was ist der beste Weg, um sicherzustellen, dass ich mich einloggen kann?
Also zum Beispiel.
%Vor%und
%Vor%Nicht sicher, ob ich die add-Methode abfangen kann, um dies zu erreichen, oder eine übergeordnete Klasse erstellen, die die java.util.List-Schnittstelle implementiert, und sie stattdessen verwendet. So oder so, ich suche nach einer guten Lösung, die minimale Intervention erfordert und vorzugsweise ohne Verwendung von Paketen von Drittanbietern ...
Ich würde das so genannte Dekorationsmuster verwenden, um Ihre Listen zu umbrechen.
Dies wäre ein einfacher Beispielcode, nur um Ihnen eine Idee zu geben:
%Vor%Es gibt nicht wirklich eine einfache Möglichkeit, dorthin zu gelangen.
Diese Klassen sind Teil der "Standardbibliotheken"; Sie können also ihr Verhalten nicht ändern. Sie könnten Ihre eigenen Versionen von ihnen erstellen. und verwenden Sie die Klassenpfad-Reihenfolge, um sie zu verwenden; aber dieser wirklich schmutzige Hack.
Die einzige andere Option: erweitern diese Klassen; @Override die Methoden, die Sie protokollieren möchten; und stellen Sie sicher, dass all Ihre Quellen Ihre eigenen Versionen dieser Klassen verwenden. Oder wenn Sie Komposition über Vererbung bevorzugen , wählen Sie das Decorator-Muster; wie von JDCs Antwort vorgeschlagen.
Die "dritte" Option ist wirklich anders - Sie wenden sich der aspektorientierten Programmierung zu (zum Beispiel mit AspectJ) und verwenden solche Werkzeuge, um Dinge auf Bytecodeebene zu manipulieren. Aber das bringt Ihrem Produkt eine ganz neue Ebene von "Komplexität". also ich zähle es nicht als echte Option.
BEARBEITEN Sie Ihre Antwort: Es scheint, dass Sie den Unterschied zwischen Interface und Implementierung nicht verstehen ?! Eine Schnittstelle beschreibt einfach eine Reihe von Methodensignaturen; Um jedoch echten Code hinter diesen Methoden zu haben, muss eine Implementierungsklasse vorhanden sein. Du siehst, wenn du es tust
%Vor% Der echte Typ von things
ist ArrayList; aber Sie interessieren sich selten für diesen echten Typ; Es ist gut genug zu wissen, dass Sie all diese List-Methoden auf things
haben können. Wenn Sie also eine neue Implementierung der List-Schnittstelle erstellen ... wirkt sich dies nicht auf vorhandene
Erklärungen überhaupt. Sie müssten alle Zuweisungen zu
ändern %Vor% JDC hat einen guten Weg gegeben, zu folgen.
Ich möchte wichtige Präzisionen bringen.
Das Decorator-Muster ermöglicht es, eine Klasse zu erstellen, die eine andere Klasse ziert, indem einer Instanz dynamisch eine neue Verantwortung hinzugefügt oder daraus entfernt wird.
In Ihrem Fall möchten Sie Verantwortung hinzufügen.
Decorator ist kein aufdringliches Muster, aber die Decorator-Klasse muss der Klasse entsprechen, die sie dekoriert.
In Ihrem Fall entspricht also ein Decorator, der von der Schnittstelle Collection
abgeleitet wird, nicht dem dekorierten Objekt, da List
Methoden hat, die Collection
nicht hat.
Ihr Bedarf besteht darin, List
instances zu dekorieren, daher sollte der Decorator vom Typ List
abgeleitet werden.
Außerdem kann die Dekoratorklasse je nach ihren Bedürfnissen eine Verarbeitung vor und nach der Operation der Klasse, die sie dekoriert, ausführen, aber sie ist auch dafür verantwortlich, die ursprüngliche Operation der dekorierten Klasse aufzurufen.
In Ihrem Fall möchten Sie wissen, ob ein Element zur Liste hinzugefügt oder aus der Liste entfernt wurde. Um dies zu erreichen, da das Ergebnis der Methode Auswirkungen darauf hat, ob Sie die Informationen protokollieren oder nicht, ist es vorzuziehen, zuerst die Verarbeitung an das dekorierte Objekt zu delegieren, und dann kann Ihr Decorator seine Verarbeitungen ausführen
Manchmal müssen Sie eine Methode nicht dekorieren, tun Sie es nicht, aber vergessen Sie nicht, das dekorierte Objekt entsprechend zu delegieren.
Wie gesagt, ein Dekorateur ist nicht aufdringlich für die dekorierten Objekte.
Die Idee ist also nicht, den Code zu ändern, der funktioniert, sondern den Dekorationsvorgang direkt nach der Instanziierung der Liste hinzuzufügen.
Wenn Sie bei der Deklaration Ihrer Listenvariablen nicht nach Schnittstelle programmieren, also ArrayList list = new ArrayList()
anstelle von List list = new ArrayList()
deklarieren, sollten Sie natürlich den deklarierten Typ zu List ändern, aber den Code nicht brechen, im Gegenteil.
Hier ist Ihr Beispielcode:
%Vor%Jetzt könnten Sie es tun:
%Vor%Um die Aufgabe zu erleichtern und sicherer zu machen, könnten Sie sogar eine util-Methode erstellen, um die Dekoration auf die Liste anzuwenden:
%Vor%und nenne es so:
%Vor% Eine einfache Möglichkeit, dies zu erreichen, besteht darin, die Quellliste in eine ObservableList
Beispiel:
%Vor%Siehe die javafx-Dokumentation zum Hinzufügen eines guter Zuhörer
Ihre Liste ist hier die Quelle. Sie müssen die Änderungen an der Quelle verfolgen. Dies ist ein gutes und natürliches Beispiel für das Observer-Muster. Sie können ein Observable erstellen, welches Ihre Liste ist. Erstellen Sie dann einige Beobachter und registrieren Sie sie im Observable. Wenn das Observable geändert wird, benachrichtigen Sie alle registrierten Beobachter. Im Observer können Sie die Änderungen mithilfe des Eingabeereignisses protokollieren. Sie sollten hier einige ObservableCollection implementieren. Sie können Java Rx verwenden, um diese Arbeit zu erledigen. Bitte finden Sie den unten angegebenen Beispielcode.
%Vor%Hoffe, das hilft. Glückliche Kodierung!
Wir brauchen ein wenig mehr Informationen, um die richtige Lösung zu finden. Aber ich sehe eine Reihe von Optionen.
1) funktioniert, wenn Sie genau wissen, wie die Liste verwendet wird, und wenn sie an Ihren neuen Code zurückgegeben wird, sind Sie der einzige Benutzer. Daher darf der vorhandene Code keine Methoden enthalten, die zur ursprünglichen Liste hinzugefügt werden (weil add / remove für den Delegaten anstelle der dekorierten Auflistung aufgerufen würde).
2) Dieser Ansatz wird verwendet, wenn mehrere Klassen die Liste ändern können. Sie müssen in der Lage sein, eine Kopie der Liste zu erhalten, bevor irgendwelche Änderungen beginnen, und dann zu berechnen, was danach passiert. Wenn Sie Zugriff auf die Apache Collections-Bibliothek haben, können Sie mit CollectionUtils die Schnittmenge und die Disjunktion berechnen.
3) Diese Lösung benötigt einige Funktionen zum Weben (Kompilieren oder Laden von Zeit), da dies einen Proxy für jede Liste erstellt, so dass Callback-Code um die Methodenaufrufe hinzugefügt werden kann. Ich würde diese Option nicht empfehlen, es sei denn, Sie haben ein gutes Verständnis davon, wie Aspekte funktionieren, da diese Lösung eine ziemlich steile Lernkurve hat und wenn etwas schief geht und Sie Code debuggen müssen, kann es ein bisschen schwierig sein.
4) Du sagst bestehende Codebasis, die mich glauben lässt, dass du den Code tatsächlich ändern kannst, wenn du wirklich willst. Wenn dies überhaupt möglich ist, würde ich dies wählen. Wenn der Benutzer der Liste in der Lage sein muss, Änderungen zu verfolgen, besteht die bestmögliche Lösung darin, dass die Bibliothek eine ChangeTrackingList (Schnittstelle, die Methoden aus dem Tracking definiert) zurückgibt, die Sie mit Decoration erstellen können.
Eine Sache, auf die Sie achten müssen, wenn Sie dekorieren, ist, dass List eine removeAll () und eine addAll () hat, diese Methoden können add- () und remove () aufrufen, dies hängt von der Listenimplementierung ab . Wenn Sie nicht wissen, wie diese Methoden intern aufgerufen werden, können Sie ein Objekt zweimal als entfernt markieren (es sei denn, Sie können einen Satz verwenden).
Tags und Links java