## 概述 观察者模式又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种。 它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。**这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。** [观察者模式.drawio](.res/观察者模式.drawio) ![image-20220404070544142](imgs/image-20220404070544142.png) ## 简单实现 **主题接口和观察者接口** ```java //主题接口 public interface Subject { //登记 void register(Observer observer); //注销登记 void unregister(Observer observer); //通知 void notify(); } //观察者接口 public interface Observer { //更新 void update(); } ``` **实现类** ```java //主题实现类 public class TeacherComeSubject implements Subject { private List observerList = new ArrayList<>(); @Override public void register(Observer observer) { observerList.add(observer); } @Override public void unregister(Observer observer) { observerList.remove(observer); } @Override public void notfiy() { for (Observer observer : observerList) { observer.update(); } } } //打游戏学生观察者 public class StudentPlayGameObserver implements Observer { @Override public void update() { System.out.println("停止打游戏,马上写作业"); } } //聊天学生观察者 public class StudentChatObserver implements Observer { @Override public void update() { System.out.println("停止聊天,马上写作业"); } } ``` **客户端** ```java public static void main( String[] args ) { Subject subject = new TeacherComeSubject(); Observer studentChatObserver = new StudentChatObserver(); Observer studentPlayGameObserver = new StudentPlayGameObserver(); subject.register(studentChatObserver); subject.register(studentPlayGameObserver); //老师来了 subject.notfiy(); } ``` 执行结果: ``` 停止聊天,马上写作业 停止打游戏,马上写作业 ``` ## Google Guava 实现 **EventBus**是Guava中的事件处理机制,是观察者模式的优雅实现,使用起来也非常的简单。 它主要由三部分组成:事件总线、事件、事件监听 它的缺点是:只能单进程使用,项目异常重启或者退出不保证消息持久化。如果要支持分布式,还是要用MQ。 ![image-20220404120126729](imgs/image-20220404120126729.png) ### 0. 引入依赖 ```xml com.google.guava guava 20.0 ``` ### 1. 事件总线 ```java //静态工具类 public class EventBusCenter{ private static final EventBus eventBus = new EventBus(); /** * 登记事件监听 * * @param eventListener */ public static void register(EventListener eventListener) { eventBus.register(eventListener); } /** * 注销登记事件监听 * * @param eventListener */ public static void unregister(EventListener eventListener) { eventBus.unregister(eventListener); } /** * 推送事件 * * @param eventListener */ public static void post(Event event) { eventBus.post(event); } } ``` ### 2. 事件 ```java //事件接口 public interface Event { String getName(); } /** * 老师来了事件 */ public class TeacherComeEvent implements Event { /** * 事件名称 */ private String name; public TeacherComeEvent(String name) { this.name = name; } @Override public String getName() { return name; } public void setName(String name) { this.name = name; } } /** * 老师离开事件 */ public class TeacherLeaveEvent implements Event { private String name; public TeacherLeaveEvent(String name) { this.name = name; } @Override public String getName() { return name; } public void setName(String name) { this.name = name; } } ``` ### 3. 事件监听 ```java //事件监听接口 public interface EventListener { } //老师事件监听,包括老师来了事件、老师走了事件 public class TeacherEventListener implements EventListener { /** * 监听老师来了事件 * * @param event */ @Subscribe public void teacherCome(TeacherComeEvent event) { System.out.println(Thread.currentThread() + "-" + event.getName() + ":停止游戏,假装写作业"); } /** * 监听老师走了事件 * * @param event */ @Subscribe public void teacherLeave(TeacherLeaveEvent event) { System.out.println(Thread.currentThread() + "-" + event.getName() + ":停止写作业,接着玩游戏"); } } ``` ### 使用 ```java //事件监听器 EventListener eventListener = new TeacherEventListener(); //登记事件监听器 EventBusCenter.register(eventListener); //推送事件 EventBusCenter.post(new TeacherComeEvent("数学老师来了")); EventBusCenter.post(new TeacherLeaveEvent("数学老师走了")); ``` 执行结果: ``` Thread[main,5,main]-数学老师来了:停止游戏,假装写作业 Thread[main,5,main]-数学老师来了:停止写作业,接着玩游戏 ``` ### 异步处理 比如说,事件发生之后,不想立即处理,而是异步处理,只需换一个 EventBus 即可 ```java //修改EventBusCenter //private static final EventBus eventBus = new EventBus(); //异步处理事件 private static final EventBus eventBus = new AsyncEventBus(Executors.newCachedThreadPool()); ``` 观察此时的执行结果: ``` Thread[pool-1-thread-1,5,main]-数学老师来了:停止游戏,假装写作业 Thread[pool-1-thread-2,5,main]-数学老师来了:停止写作业,接着玩游戏 ```