4 Stimmen

Wie kann ich in Java einen "Proxy-Wrapper" um ein Objekt herum konstruieren, der bei der Änderung einer Eigenschaft eine Methode aufruft?

Ich suche nach etwas Ähnlichem wie die Proxy-Muster oder die Dynamische Proxy-Klassen nur, dass ich keine Methodenaufrufe abfangen möchte, bevor sie auf dem echten Objekt aufgerufen werden, sondern ich möchte Eigenschaften abfangen, die geändert werden. Ich möchte, dass der Proxy in der Lage ist, mehrere Objekte mit unterschiedlichen Eigenschaftssätzen darzustellen. Etwas wie die Proxy-Klasse in Action Script 3 wäre in Ordnung.

Folgendes möchte ich generell erreichen:

Ich habe einen Thread, der mit einem Objekt läuft, das eine Liste von Werten (Zahlen, Strings, Objekte) verwaltet, die von anderen Threads im Programm übergeben wurden, so dass die Klasse sich um die Erstellung regelmäßiger persistenter Schnappschüsse auf der Festplatte zum Zweck des Checkpointing der Anwendung kümmern kann. Dieses Persistor-Objekt verwaltet ein "Dirty"-Flag, das angibt, ob sich die Liste der Werte seit dem letzten Checkpoint geändert hat und muss die Liste sperren, während sie auf die Festplatte geschrieben wird.

Der Persistor und die anderen Komponenten identifizieren ein bestimmtes Element über einen gemeinsamen Namen, so dass die anderen Komponenten bei der Wiederherstellung nach einem Absturz zunächst prüfen können, ob der Persistor ihre letzte Kopie gespeichert hat, und dann dort weiterarbeiten können, wo sie aufgehört haben.

Während des normalen Betriebs, um mit den Objekten zu arbeiten, die sie dem Persistor übergeben haben, möchte ich, dass sie einen Verweis auf ein Proxy-Objekt erhalten, das so aussieht, als wäre es das ursprüngliche, aber wann immer sie einen Wert darauf ändern, bemerkt der Persistor dies und handelt entsprechend, z. B. indem er das Element oder die Liste als schmutzig markiert, bevor er den tatsächlichen Wert setzt.


Editar : Gibt es alternativ generische Setter (wie in PHP 5) in Java, d.h. eine Methode, die aufgerufen wird, wenn eine Eigenschaft nicht existiert? Oder gibt es eine Art von Objekt, dem ich zur Laufzeit Eigenschaften hinzufügen kann?

3voto

Michael Borgwardt Punkte 334642

Wenn Sie mit "Eigenschaften" JavaBean-Eigenschaften meinen, d. h. eine Getter- und/oder eine Setter-Methode, dann können Sie einen dynamischen Proxy verwenden, um die Set-Methode abzufangen.

Wenn Sie Instanzvariablen meinen, dann geht das nicht - nicht auf Java-Ebene. Vielleicht könnte etwas getan werden durch Manipulationen auf der Ebene des Bytecodes Allerdings.

Am einfachsten ist es wahrscheinlich, wenn Sie AspectJ und die Definition einer set()-Punktverknüpfung (die den Feldzugriff auf Bytecode-Ebene abfängt).

2voto

Alex Punkte 6665

Das gesuchte Entwurfsmuster ist: Differential Execution. Ich glaube schon.

Wie funktioniert die differenzierte Ausführung?

Ich habe eine Frage beantwortet, die sich mit diesem Thema befasst.

Darf ich jedoch vorschlagen, dass Sie stattdessen einen Rückruf verwenden? Sie müssen sich darüber informieren, aber die allgemeine Idee ist, dass Sie Schnittstellen (oft Hörer genannt) implementieren können, die aktiv werden, wenn "etwas Interessantes" passiert. Zum Beispiel, wenn eine Datenstruktur geändert wird.

Obligatorische Links:

Wiki Differenzierte Ausführung

Wiki-Rückruf

Nun gut, hier ist die Antwort, wie ich sie sehe. Differentielle Ausführung ist O(N) Zeit. Das ist wirklich vernünftig, aber wenn das für Sie nicht funktioniert, dann tun es Callbacks. Rückrufe funktionieren im Grunde so, dass eine Methode als Parameter an die Klasse übergeben wird, die das Array verändert. Diese Methode nimmt den geänderten Wert und die Position des Elements, übergibt es per Parameter an die "Speicherklasse" zurück und ändert den Wert entsprechend. Sie müssen also jede Änderung durch einen Methodenaufruf unterstützen.

Ich weiß jetzt, dass das nicht das ist, was Sie wollen. Was es scheint, dass Sie wollen, ist eine Möglichkeit, dass Sie eine Art von Listener auf jede Variable in einem Array, die aufgerufen werden würde, wenn das Element geändert wird, liefern können. Der Listener würde dann das entsprechende Array in Ihrem "Backup" ändern, um diese Änderung zu reflektieren.

Auf nativer Ebene kann ich mir keine Möglichkeit vorstellen, dies zu tun. Sie können natürlich Ihre eigenen Listener und Ereignisse erstellen, mit einer Schnittstelle. Dies ist im Grunde die gleiche Idee wie die Rückrufe, obwohl schöner zu sehen.

Dann gibt es noch die Reflexion... Java hat Reflexion, und ich bin sicher, dass Sie damit etwas schreiben können, um dies zu tun. Allerdings ist Reflection notorisch langsam. Ganz zu schweigen davon, dass es (meiner Meinung nach) eine Qual ist, zu programmieren.

Ich hoffe, das hilft...

1voto

Damien B Punkte 1972

Ich möchte keine Methodenaufrufe abfangen, bevor sie auf dem echten Objekt aufgerufen werden, sondern vielmehr möchte ich Eigenschaften abfangen, die geändert werden

Die zu überwachenden Objekte sind also keine praktischen Beans, sondern eine Wiederauferstehung der C-Strukturen. Die einzige Möglichkeit, die mir dazu einfällt, ist die Verwendung der Feldzugriffsaufruf in JVMTI .

1voto

Goran Jovic Punkte 9240

Ich wollte dasselbe tun. Meine Lösung war die Verwendung von dynamischen Proxy-Wrappern mit Javassist. Ich würde eine Klasse generieren, die dieselbe Schnittstelle implementiert wie die Klasse meines Zielobjekts, meine Proxyklasse um die Originalklasse wickeln und alle Methodenaufrufe auf dem Proxy an das Original delegieren, mit Ausnahme von Settern, die auch das PropertyChangeEvent auslösen würden.

Jedenfalls habe ich die vollständige Erklärung und den Code in meinem Blog hier veröffentlicht: http://clockwork-fig.blogspot.com/2010/11/javabean-property-change-listener-with.html

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X