在Java 8中,我想编写一个类,给定一个或多个侦听器,将返回一个代理的List(通过传入其类,使用我选择的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;
}
}
它有效,但肯定不是没有它的问题。
Class<? extends List<T>>
收到错误,因此我使用U代表? extends List<T>
。 ListInvocationHandler
的调用方法中,我不得不将Object
强制转换为T
。我认为这是不可避免的,但我欢迎任何替代方案。newProxyInstance
正在返回Object
,我必须转发List
。我相信这也是不可避免的,但我欢迎任何替代方案。我正在使用的主要内容如下:
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"));
});
我为文字墙道歉。我很感激任何意见。
答案 0 :(得分:3)
您可以使用装饰器而且可能摆脱(几乎)所有这些警告:
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>() { ... } );
...或创建工厂方法。