简体   繁体   English

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

[英]Using method references as listeners with observer pattern

the usage of method references as listeners in an observer pattern does not work.在观察者模式中使用方法引用作为监听器是行不通的。 Example:例子:

    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());
    }
}

Conclusion: each referencing of the listener method with ml::theListener generates a new object id for the reference?结论:每次使用 ml::theListener 引用监听器方法都会生成一个新的 object id 以供引用? Right?正确的? Therefore there a multiple listeners registered and cannot be removed individually?因此,注册了多个侦听器并且不能单独删除?

The MyListenerWorks class uses a member with a "constant" object id and works. MyListenerWorks class 使用具有“常量” object id 的成员并工作。 Is there another workaround for this?还有其他解决方法吗? Are my assumptions correct?我的假设是否正确?

From the Oracle documentation on Method References:来自关于方法参考的 Oracle 文档

Method references enable you to do this;方法引用使您能够做到这一点; they are compact, easy-to-read lambda expressions for methods that already have a name.它们是紧凑的、易于阅读的 lambda 表达式,用于已经有名称的方法。

A method reference is not a constant .方法引用不是常量

After I added some breakpoints to the HashSet#add and remove function. I got some results for your questions in the images below:在我向 HashSet#add 和 remove function 添加了一些断点之后。我在下图中得到了一些针对您的问题的结果:

在此处输入图像描述

1. each referencing of the listener method with ml::theListener generates a new object id for the reference? 1. 每次使用 ml::theListener 引用监听器方法都会生成一个新的 object id 作为引用? Right?正确的?

Ans: No. It would generate a new memory address into the HashSet. Ans:不会。它会在 HashSet 中生成一个新的 memory 地址。 There would not be an object id.不会有 object id。 So in the test function:testListenerLeak, you cannot remove the listener correspondingly.所以在测试function:testListenerLeak中,不能对应的去掉监听。 Since you didn't get the listeners from the set before you remove it.因为在删除它之前你没有从集合中得到听众。

2. The MyListenerWorks class uses a member with a "constant" object id and works. 2. MyListenerWorks class 使用具有“常量”object id 的成员并工作。 Is there another workaround for this?还有其他解决方法吗? Are my assumptions correct?我的假设是否正确?

You could take a look of the Observer pattern in Spring, Vue, or some other famous project.你可以看看 Spring、Vue 或其他一些著名项目中的观察者模式。 they have something similar to what you want.他们有类似于你想要的东西。 But mostly I have ever read about this pattern is in the Event-driven model. They use the "instanceOf" to check the subclasses and their superclass.但我读过的关于这种模式的大部分内容是在事件驱动的 model 中。他们使用“instanceOf”来检查子类及其超类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM