代理混乱的优雅解决方案
问题描述:
在Java 8中,我想编写一个类,给定一个或多个侦听器,每当返回一个代理列表(使用通过传入其类的实现List来选择)东西被添加或删除。代码(与我一起)如下:代理混乱的优雅解决方案
public final class EventedList {
private EventedList() {
}
protected static class ListInvocationHandler<T> implements InvocationHandler {
private List<T> theList;
private ListChangeHandler<T>[] listeners;
public ListInvocationHandler(Class<? extends List<T>> listClass, ListChangeHandler<T>[] listeners) throws InstantiationException, IllegalAccessException {
this.listeners = listeners;
theList = listClass.newInstance();
}
public Object invoke(Object self, Method method, Object[] args)
throws Throwable {
Object ret = method.invoke(theList, args);
switch(method.getName()) {
case "add":
trigger((T)args[0], true);
break;
case "remove":
if(args[0] instanceof Integer) {
trigger((T)ret, false);
} else {
trigger((T)args[0], false);
}
break;
}
return ret;
}
public void trigger(T obj, boolean added) {
Arrays.stream(listeners).forEachOrdered(l -> l.onChange(obj, added));
}
}
public static <T, U extends List<T>> List<T> newList(Class<U> listClass, ListChangeHandler<T> ... listeners) throws IllegalArgumentException, InstantiationException, IllegalAccessException {
@SuppressWarnings("unchecked")
List<T> obj = (List<T>)Proxy.newProxyInstance(listClass.getClassLoader(), new Class<?>[]{List.class}, new ListInvocationHandler<T>(listClass, listeners));
return obj;
}
public static <T, U extends List<T>> List<T> newListSafe(Class<U> listClass, ListChangeHandler<T> ... listeners) {
List<T> obj = null;
try {
obj = newList(listClass, listeners);
} catch (IllegalArgumentException | InstantiationException
| IllegalAccessException e) {
}
return obj;
}
}
它的作品,但它肯定不是没有它的问题。
- 我最初只有一个类型T,但使用
Class<? extends List<T>>
错误我得到,所以我用U表示? extends List<T>
代替。 - 在调用方法
ListInvocationHandler
时,我不得不将Object
强制转换为T
。我认为这是不可避免的,但我欢迎任何替代方案。 -
newProxyInstance
正在返回Object
我不得不将其投射到List
。此外,我相信这是不可避免的,但我欢迎任何替代品。 - 我收到“通过varargs参数侦听器的潜在堆污染”警告听众参数大概是因为它们是可变参数参数,但我没有看到这样做的明显风险。
主要我使用如下:
public static void main(String[] args) {
List<String> list = EventedList.newListSafe(ArrayList.class, new ListChangeHandler<String>() {
@Override
public void onChange(String value, boolean added) {
System.out.println(value + ", " + (added ? "added" : "removed"));
}
});
list.add("Badger"); // Badger, added
list.add("Badger"); // Badger, added
list.add("Badger"); // Badger, added
list.add("Badger"); // Badger, added
list.remove("Badger"); // Badger, removed
list.add("Mushroom"); // Mushroom, added
list.remove("Mushroom"); // Mushroom, removed
// [Badger, Badger, Badger]
System.out.println(Arrays.toString(list.toArray()));
}
- 主要本身调用该方法有一个很好的类型安全警告,即使参数应该是隐含的。
-
如果可能的话,我希望能够调用它,如下所示(虽然我收到一个错误等):
List<String> list = EventedList.newListSafe(ArrayList.class, (value, added) -> { System.out.println(value + ", " + (added ? "added" : "removed")); });
我对文字的墙道歉。我很欣赏任何输入。
答
你可以使用一个装饰器,并可能摆脱(几乎)所有这些警告:
class EventedList<E> implements List<E> {
private List<E> delegate;
private List<ListChangeHandler<E>> listeners;
//using varargs here would still cause the heap pollution warning
public EventedList(List<E> d, ListChangeHandler<E>... l) {
//set and initialize
}
public boolean add(E e) {
delegate.add(e);
trigger(e);
}
... //other methods
private void trigger(E e) {
//trigger listeners
}
然后,只需调用它
List<String> list = new EventedList<String>(new ArrayList<String>(),
new ListChangeHandler<String>() { ... });
...或创建一个工厂方法。
为什么不提供供应商:'EventedList.newList(ArrayList :: new,...)'并避免反射混乱? – assylias
为什么不使用委托并将新列表传递给构造函数? – Thomas
@assylias我甚至没有考虑过使用供应商,但这是一个体面的想法,谢谢。 – Neil