观察者模式:在对象之间定义了一对多的依赖,当一个对象改变状态,依赖它的对象会收到通知并自动更新。其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。
观察者模式应用场景
Spring的ApplicationEvent、Zk事件通知节点、消息订阅通知、安卓开发事件注册、分布式配置中心nacos config配置刷新、异步事件驱动
观察者模式原理类图
抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
观察者模式简单的实现,案例一:
模拟运维平台给运维人员推送Alter 异常警告
抽象观察者
public interface Observer { /** *通知观察者消息 * @param message */ void sendMessage(String message); }
抽象主题者
public abstract class BrianSubject { /** * 添加观察者 * @param observer */ public abstract void addObserver(Observer observer); /** * 移除观察者 * @param observer */ public abstract void removeObserver(Observer observer); /** * 通知消息 * @param message */ public abstract void notifyObserver(String message); }
具体主题
@Component public class AlertSubject extends BrianSubject { private List<Observer> observerList ; private ExecutorService executorService; public AlertSubject() { this.observerList = new ArrayList<>(); this.executorService = Executors.newFixedThreadPool(10); } @Override public void addObserver(Observer observer) { observerList.add(observer); } @Override public void removeObserver(Observer observer) { observerList.remove(observer); } @Override public void notifyObserver(String message) { observerList.forEach(observer -> { executorService.execute(() -> observer.sendMessage(message)); }); } }
具体观察者
@Component @Slf4j public class AlertEmailObserver implements Observer { /** * 邮件通知运维 * @param message */ @Override public void sendMessage(String message) { log.info("邮件通知运维人员: {}",message); } } @Component @Slf4j public class AlertSlackObserver implements Observer { /** * Slack 通知运维 * @param message */ @Override public void sendMessage(String message) { log.info("Slack通知运维人员: {}",message); } } @Component @Slf4j public class AlertSmsObserver implements Observer { /** * 短信通知运维 * @param message */ @Override public void sendMessage(String message) { log.info("短信通知运维人员: {}",message); } }
运行测试
@RestController public class TestObserverController { @Autowired private ApplicationContext applicationContext; @Autowired private AlertSubject alertSubject; /** * 模拟运维平台 通知运维人员 * @param message * @return */ @GetMapping("/testAlertMessage") public ResponseEntity<?> order(@RequestParam String message){ alertSubject.notifyObserver(message); return new ResponseEntity<>("消息已经发出", HttpStatus.OK); } /** * 模拟用户订票通知用户 * @return */ @GetMapping("/order") public ResponseEntity<?> order(){ Map<String, String> map = new HashMap<>(); map.put("orderId","QW12345676545"); map.put("content","2020-07-01 慕尼黑 -> 香港 KA800 航班"); map.put("price","$1000"); OrderMessageEvent orderMessageEvent = new OrderMessageEvent(this,map); applicationContext.publishEvent(orderMessageEvent); return new ResponseEntity<>(map, HttpStatus.OK); } }
基于Spring封装事件监听实现通知,案例二
模拟用户订购机票后通知用户
Spring实现事件通知,底层采用观察者模式封装的
// 定义事件,即发送的消息
public class OrderMessageEvent extends ApplicationEvent { //群发消息的内容 private Map map; public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } public OrderMessageEvent(Object source, Map map) { super(source); this.map = map; } } // 定义监听类 @Component public class EmailListener implements ApplicationListener<OrderMessageEvent> { @Override @Async public void onApplicationEvent(OrderMessageEvent orderMessageEvent) { System.out.println(Thread.currentThread().getName() + " 发送邮件消息:" + orderMessageEvent.getMap().toString()); } } @Component public class SmsListener implements ApplicationListener<OrderMessageEvent> { @Override @Async public void onApplicationEvent(OrderMessageEvent orderMessageEvent) { System.out.println(Thread.currentThread().getName() + " 发送短信消息:" + orderMessageEvent.getMap().toString()); } } @Component public class WechatListener implements ApplicationListener<OrderMessageEvent> { @Override @Async public void onApplicationEvent(OrderMessageEvent orderMessageEvent) { System.out.println(Thread.currentThread().getName() + " 发送微信通知消息:" + orderMessageEvent.getMap().toString()); } }
// 发布消息
/**
* 模拟用户订票通知用户
* @return
*/
@GetMapping("/order")
public ResponseEntity<?> order(){
Map<String, String> map = new HashMap<>();
map.put("orderId","QW12345676545");
map.put("content","2020-07-01 慕尼黑 -> 香港 KA800 航班");
map.put("price","$1000");
OrderMessageEvent orderMessageEvent = new OrderMessageEvent(this,map);
applicationContext.publishEvent(orderMessageEvent);
return new ResponseEntity<>(map, HttpStatus.OK);
}
测试结果
观察者模式的优点
1、去重复代码,使得代码更清晰、更易读、更易扩展
2、解耦,使得代码可维护性更好,修改代码的时候可以尽量少改地方
使用观察者模式可以很好地做到这两点。增加观察者,直接new出观察者并注册到主题对象之后就完事了,删除观察者,主题对象调用方法删除下就OK了,其余都不用管。主题对象状态改变,内部会自动帮我们通知每一个观察者.