定义
当一个对象的状态发生变化时,所有依赖它的对象都被通知并自动更新。
UML类图及观察者模式的说明如上图所示(图片来源《head根据_first设计模式),观察者的uml主要包括以下类别
1.主题Subject(接口)
Subject 对象带绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法主要是观察者的注册方法(registerObserver),观察者删除方法(removeObserver),通知观察者方法(notifyObservers)
2.Observer(接口)观察者
Observer观察者通常是一个接口,每个实现该接口的实现类都是特定的观察者。主要提供update方法。
3.ConcreteSubject(Subject的具体实现)
是主题Subject接口的具体实现,可以根据具体业务进行扩展
4.具体观察者Concreteobserver(Observer的具体实现)
这是Observer观察者的具体实现。一般来说,会有多个订阅者,所以这种类型可以通过他们需要的信息来扩展
观察者模式的优缺点和应用场景优点:
1.观察者和观察者是抽象耦合的。
2.建立一套触发机制。
缺点:
1.如果一个观察者有很多直接和间接的观察者,那么通知所有的观察者需要很多时间。
2.若观察者与观察者之间存在循环依赖,则观察者可能会触发它们之间的循环调用,从而导致系统崩溃。
3.观察者模式没有相应的机制让观察者知道观察到的目标是如何改变的,而只知道观察到的目标是如何改变的。
应用场景:
1.关联行为场景
2.事件多级触发场景
4.跨系统的信息变换场景,如信息队列的处理机制
应用实例:
1.新闻发布订阅
2.天气信息发布订阅
注意事项:
1、JAVA 对观察者模式有支持。
2、避免循环引用。
3、若顺序执行,观察者的错误会导致系统卡壳,一般采用异步法。
Spring中的观察者模式1.事件(ApplicationEvent)
ApplicationEvent 是所有事件对象的父类。ApplicationEvent 继承自 jdk 的 EventObject, 所有事件都需要继承 ApplicationEvent, 并通过source获得事件源。
2.事件监听(ApplicationListener)
ApplicationListener 事件监听器,即观察者。继承 jdk 的 EventListener,这一类只有一种方法 onApplicationEvent。当监控事件发生时,该方法将被执行。
3.事件发布(ApplicationContext)
ApplicationContext 是 Spring 事件监控中的核心容器 ApplicationContext 它可以作为事件的出版商,即事件的来源。因为 ApplicationContext 继承自 ApplicationEventPublisher。在 ApplicationEventPublisher 定义了事件发布的方法 — publishEvent(Object event)
4.事件管理(ApplicationEventMulticaster)
ApplicationEventMulticaster 用于事件监听器的注册和事件的广播。监听器的注册是通过它来实现的,它的作用是使用 Applicationcontext 发布的 Event 广播给它的监听器列表。
实现观察者模式现在在线直播模式非常流行。在这里,以简单的LOL游戏信息订阅为例。例如,我们应该关注今天的LPL游戏信息和未来几天的游戏信息。我们可以点击订阅。订阅后,如果有新的游戏信息,我们会把它推给你。
在这种情况下,我们可以使用观察者模式来实现:
定义主题界面
/** * 主题界面,对象通过此界面注册为观察者,或者从观察者中删除自己 * * @author yyl */public interface Subject { /** * 观察者注册 * */ void registerObserver(Observer observer); /** * 删除观察者 * */ void removeObserver(Observer observer); /** * 通知观察者 * */ void notifyObservers();}
定义主题界面的具体实现和LOL竞赛信息主题
/** * lol主题 * * @author yyl */public class LolSubject implements Subject { /** 今日比赛信息*/ private String msg; /** 几天后的比赛信息*/ private List<String> msgList; // 用户列表 private static List<Observer> userList = new ArrayList<>(); @Override public void registerObserver(Observer observer) { userList.add(observer); } @Override public void removeObserver(Observer observer) { userList.remove(observer); } @Override public void notifyObservers() { userList.forEach(observer -> observer.update()); } /** * 发布信息,并通知观察者 * * @author yyl */ public void setMsgs(String msg,List<String> msgList){ // 更改通知信息 this.msg = msg; this.msgList = msgList; // 通知观察者 notifyObservers(); } public String getMsg() { return msg; } public List<String> getMsgList() { return msgList; }}
Observerer定义观察者
/** * 观察者Observer,观察者通常是一个接口,每个实现接口的实现类都是具体的观察者 * * @author yyl */public interface Observer { /** * 接收消息后的具体逻辑处理 */ void update();}
具体观察者,今天的比赛信息观察者
/** * 具体观察者,今天的比赛信息观察者 * * @author yyl */public class CurrentObserver implements Observer { /**lol竞赛信息主题 */ private LolSubject subject; /**订阅信息 */ private String msg; public CurrentObserver(LolSubject subject) { this.subject = subject; // 观察者注册 this.subject.registerObserver(this); } @Override public void update() { this.msg = this.subject.getMsg(); System.out.println("今日比赛:" + this.msg); }}
具体观察者,游戏信息观察者在接下来的几天里
/** * 具体观察者,比赛信息观察者在接下来的几天里观察了比赛信息 * * @author yyl */public class FutureObserver implements Observer { **lol比赛信息主题 */ private LolSubject subject; /**订阅信息 */ private List<String> msgList; public FutureObserver(LolSubject subject) { this.subject = subject; // 观察者注册 this.subject.registerObserver(this); } @Override public void update() { this.msgList = this.subject.getMsgList(); System.out.println(“比赛预告:”; msgList.forEach(s -> System.out.println(s)); }}
通知者进行通知 Client
public class TestObserver { public static void main(String[] args) { // 主题 LolSubject lolSubject = new LolSubject(); // 观察者 CurrentObserver currentObserver = new CurrentObserver(lolSubject); FutureObserver futureObserver = new FutureObserver(lolSubject); List<String> msgList = new ArrayList<>(); msgList.add("2020-06-22 RNG VS IG"); msgList.add("2020-06-22 VG VS LGD"); msgList.add("2020-06-22 V5 VS OMG"); // 发布信息 lolSubject.setMsgs("TSE VS FPX", msgList); }}
例如,在上述代码中,有两个观察者在发布信息的竞争信息后,观察者可以获得他们关注的信息,然后处理他们自己的业务逻辑。代码输出如下