代理混乱的优雅解决方案

时间:2016-02-26 15:27:02

标签: java reflection java-8

在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;
    }   
}

它有效,但肯定不是没有它的问题。

  1. 我最初只有一个类型T,但我使用Class<? extends List<T>>收到错误,因此我使用U代表? extends List<T>
  2. ListInvocationHandler的调用方法中,我不得不将Object强制转换为T。我认为这是不可避免的,但我欢迎任何替代方案。
  3. newProxyInstance正在返回Object,我必须转发List。我相信这也是不可避免的,但我欢迎任何替代方案。
  4. 我收到一个“通过varargs参数监听器的潜在堆污染”警告听众参数可能是因为它们是可变参数参数,但是我没有看到以这种方式这样做的明显风险。
  5. 我正在使用的主要内容如下:

    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()));  
    }
    
    1. 主要调用方法本身有一个很好的类型安全警告,即使参数应该是隐式的。
    2. 如果可能的话,我希望能够按如下方式调用它(虽然我收到错误):

      List<String> list = EventedList.newListSafe(ArrayList.class, (value, added) -> {
          System.out.println(value + ", " + (added ? "added" : "removed"));
      });
      
    3. 我为文字墙道歉。我很感激任何意见。

1 个答案:

答案 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>() { ... } );

...或创建工厂方法。