观察者模式中的角色可以分为Subject和Observer,它们分别为被观察者和观察者,观察者观察被观察者的状态变更。google的guava中提供了EventBus功能,EventBus可以实现观察者模式,下面是一个简单的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe;
public class TestEventBus {
public static void main(String[] args) { EventBus eventBus = new EventBus("test"); eventBus.register(new Listener()); eventBus.post(new Event("hello, world")); }
}
class Event { public String message;
Event(String message) { this.message = message; } }
class Listener { @Subscribe public void listen(Event event) { System.out.println(event.message); } }
|
我们也可以自己实现一个EventBus,虽然在效率上没办法和google的实现相比,但是基本原理都是一样的。
首先我们创建一个用于标记方法是否需要实现订阅的注解
1 2 3 4
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Subscribe { }
|
随后创建EventBus的核心类,其主要功能是添加或移除listener,以及根据传入的参数对符合要求的方法进行调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class EventBus {
private Set<Object> listeners = new HashSet<>();
public void register(Object listener) { listeners.add(listener); }
public void unregister(Object listener) { listeners.remove(listener); }
public void post(Object event) { for (Object listener : listeners) { Method[] methods = listener.getClass().getDeclaredMethods(); for (Method method : methods) { if (method.isAnnotationPresent(Subscribe.class)) { Class[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1 && parameterTypes[0] == event.getClass()) { try { method.invoke(listener, event); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } } } } } }
}
|
最后我们对上面的实现进行测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Test {
public static void main(String[] args) { EventBus eventBus = new EventBus(); eventBus.register(new Listener()); eventBus.post("Mike"); }
}
class Listener { @Subscribe public void say(String name) { System.out.println("hello, " + name); } }
|
测试代码打印出了如下结果
hello, Mike
参考:
https://juejin.im/post/5b61c852e51d451956055476
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/25
本文链接:
https://www.nosuchfield.com/2019/06/24/Observer-mode/