使用方法引用作为具有观察者模式的侦听器
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.
在观察者模式中将方法引用用作侦听器是行不通的。 示例:
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.