Während C# Sprachunterstützung für Delegation und Ereignisse in Java hat, müssen wir entweder anonyme innere Klassen für die Bindung verwenden oder Reflection Code verwenden http://oatv.com/pub/a/onjava/2003/05/21/delegates.html . In den Kommentaren dieser Seite gibt es einen Hinweis auf CGLib Multicast Delegates, aber Google Codes scheinen keinen Beispielcode für diese Klasse zu kennen. Hat jemand einen Link zu einem funktionierenden Beispiel sonst hat eine an ihren Fingerspitzen?
Antwort
Zu viele Anzeigen?Ich weiß, dass diese Frage schon alt ist, aber vielleicht fragt sich jemand eines Tages dasselbe. Für eine normale C#
-ähnlichen Delegaten, würden Sie wahrscheinlich die MethodDelegate
, nicht die MulticastDelegate
. Nehmen wir an, wir haben eine einfache Java POJO Bean:
public class SimpleBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
dann können wir einen instrumentierten (nicht-reflektierenden) Delegaten wie diesen erstellen:
public static interface BeanDelegate {
String getValueFromDelegate();
}
@Test
public void testMethodDelegate() throws Exception {
SimpleBean bean = new SimpleBean();
bean.setValue("Hello world!");
BeanDelegate delegate = (BeanDelegate) MethodDelegate.create(
bean, "getValue", BeanDelegate.class);
assertEquals("Hello world!", delegate.getValueFromDelegate());
}
Bei diesem Beispiel gibt es einige Dinge zu beachten:
-
Die Fabrikmethode
MethodDelegate#create
nimmt genau einen Methodennamen als zweites Argument. Dies ist die Methode, dieMethodDelegate
wird für Sie stellvertretend arbeiten. -
Es muss eine Methode geben sin Argumente, die für das Objekt definiert sind, das der Fabrikmethode als erstes Argument übergeben wird. Somit ist die
MethodDelegate
ist nicht so stark, wie sie sein könnte. -
Das dritte Argument muss eine Schnittstelle mit genau einem Argument sein. Die
MethodDelegate
implementiert diese Schnittstelle und kann auf sie übertragen werden. Wenn die Methode aufgerufen wird, ruft sie die Proxy-Methode für das Objekt auf, das das erste Argument ist.
Es gibt einige Nachteile/Fallstricke:
-
CGlib erstellt für jeden Proxy eine neue Klasse. Dies führt dazu, dass der Heap-Speicherplatz für die permanente Generierung voll wird. (Das kann auf lange Sicht Probleme verursachen.)
-
Sie können keine Proxy-Methoden verwenden, die Argumente annehmen. (Das nervt.)
-
Wenn Ihre Schnittstelle Argumente benötigt, funktioniert die Delegation der Methode einfach nicht, ohne dass eine Ausnahme ausgelöst wird (der Rückgabewert ist dann immer
null
). Wenn Ihre Schnittstelle einen anderen Rückgabetyp erfordert (auch wenn dieser allgemeiner ist), erhalten Sie eineIllegalArgumentException
. (Das ist seltsam.)
En MulticastDelegate
funktioniert ein wenig anders. Diesmal brauchen wir eine Bean, die tatsächlich eine Schnittstelle mit einer einzigen Methode implementiert:
public class SimpleMulticastBean implements DelegatationProvider {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public interface DelegatationProvider {
void setValue(String value);
}
Dieses Mal wird die Schnittstelle - genannt DelegatationProvider
im Beispiel - muss eine einzige Methode anbieten (wie zuvor). Diese Schnittstelle muss von jedem Objekt implementiert werden, das zu diesem Delegationsproxy hinzugefügt wird. Dies kann wie folgt geschehen:
@Test
public void testMulticastDelegate() throws Exception {
MulticastDelegate multicastDelegate = MulticastDelegate.create(
DelegatationProvider.class);
SimpleMulticastBean first = new SimpleMulticastBean();
SimpleMulticastBean second = new SimpleMulticastBean();
multicastDelegate = multicastDelegate.add(first);
multicastDelegate = multicastDelegate.add(second);
DelegatationProvider provider = (DelegatationProvider)multicastDelegate;
provider.setValue("Hello world!");
assertEquals("Hello world!", first.getValue());
assertEquals("Hello world!", second.getValue());
}
Auch diese Umsetzung hat ihre Nachteile:
-
Die Objekte müssen eine Schnittstelle mit einer einzigen Methode implementieren. Das ist schlecht für Bibliotheken von Drittanbietern und ist umständlich, wenn Sie CGlib verwenden, um einige Magie wo diese Magie der Öffentlichkeit zugänglich gemacht wird normaler Code . Außerdem könnten Sie Ihren eigenen Delegaten leicht implementieren (ohne Bytecode, aber ich bezweifle, dass Sie so viel über die manuelle Delegation gewinnen).
-
Wenn Ihre Delegierten einen Wert zurückgeben, erhalten Sie nur den Wert des letzten Delegierten, den Sie hinzugefügt haben. Alle anderen Rückgabewerte gehen verloren (werden aber irgendwann vom Multicast-Delegaten abgerufen).
Für weitere Lektüre : Ich habe mich inspirieren lassen und fasse zusammen alles, was ich über cglib weiß, in einem Blog-Artikel .