使用方法引用作为具有观察者模式的侦听器

Using method references as listeners with observer pattern

在观察者模式中将方法引用用作侦听器是行不通的。 示例:

    public class ObserverWithMethodReferenceAsListenerTest {

    class ListenerCurator {

        private final Set<Consumer<String>> listeners = new HashSet<>();

        public boolean register(final Consumer<String> consumer) {
            return this.listeners.add(consumer);
        }

        public boolean unregister(final Consumer<String> consumer) {
            return this.listeners.remove(consumer);
        }

        public int getListenersCount() {
            return this.listeners.size();
        }

    }

    class MyListenerLeaks {

        public void theListener(final String someString) {
            // the listener
        }
    }

    class MyListenerWorks {

        public Consumer<String> consumer = str -> {
            theListener(str);

        };

        public void theListener(final String someString) {
            // the listener
        }
    }

    @Test
    public void testListenerLeak() {

        ListenerCurator lc = new ListenerCurator();
        MyListenerLeaks ml = new MyListenerLeaks();

        lc.register(ml::theListener);
        Assert.assertEquals(1, lc.getListenersCount());

        lc.register(ml::theListener);
        // expected 1 but there are 2 listeners

        lc.unregister(ml::theListener);
        // there are 2 listeners registered here

    }

    @Test
    public void testListenerWorks() {
        ListenerCurator lc = new ListenerCurator();
        MyListenerWorks ml = new MyListenerWorks();

        lc.register(ml.consumer);
        Assert.assertEquals(1, lc.getListenersCount());

        lc.register(ml.consumer);
        Assert.assertEquals(1, lc.getListenersCount());

        lc.unregister(ml.consumer);
        Assert.assertEquals(0, lc.getListenersCount());
    }
}

结论:每次使用 ml::theListener 引用监听器方法都会为引用生成一个新的对象 ID?正确的?因此注册了多个监听器,不能单独删除?

MyListenerWorks class 使用具有“常量”对象 ID 的成员并工作。还有其他解决方法吗?我的假设是否正确?

来自 Oracle documentation 方法参考:

Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.

方法引用不是常量

在我向 HashSet#add 和 remove 函数添加一些断点之后。 针对您的问题,我在下图中得到了一些结果:

1.每次使用 ml::theListener 引用侦听器方法都会为引用生成一个新的对象 ID?对吧?

Ans:不会。它会在HashSet中生成一个新的内存地址。不会有对象 ID。所以在测试function:testListenerLeak中,不能相应的去掉listener。因为在删除之前您没有从集合中获取听众。

2。 MyListenerWorks class 使用具有“常量”对象 ID 的成员并起作用。还有其他解决方法吗?我的假设正确吗?

您可以看看 Spring、Vue 或其他一些著名项目中的观察者模式。他们有类似于你想要的东西。但我读到的关于这种模式的大部分是在 Event-driven 模型中。他们使用“instanceOf”来检查 subclasses 及其 superclass.