最近有个需求,大概是想用一下观察者模式/或者是监听器模式,来实现一下。那问题来了什么是观察者模式,什么是监听器模式?两者之间有哪些联系和不同。具体实现是什么样的,那就听我讲解一下。
首先做一个总结,监听器模式实际上是在观察者模式的基础上进一步的封装。
首先是观察者模式,观察者模式分为两部分,观察者Observer和被观察者。观察者根据被观察者作为事件源,当执行逻辑涉及到触发逻辑,调用观察者的相关逻辑。
监听器相对来说多了个事件event,根据事件去监听。相当于是三部分EventSource事件源(有的地方也叫做register注册中心),Event事件(创建事件调动监听逻辑),Listener(监听器);
我这里借了一个别人的图:
代码的地址我放在我的github上:
girhub:monitor和observer对应的实现,监听器那个模式由于是接口不是抽象类,可能有的idea会报错,但是可以执行,有时间我再修改一版
观察者:对应的是两部分Subject和Observer,一个是主体,观察者类似订阅者一样去订阅自己的主题。
被观察者或者说是主题的接口以及它的实现类
package com.example.test.observer;
import java.util.List;
/**
* @Author: zhangpeng
* @Description:
* @Date: 2022/4/29
* @Desc:subject 被观察者(主题发布的主题)
*/
public interface Subject {
/**
* 添加观察者
* @return
*/
public List addObserver(Observer observer);
/**
* 删除某个观察者
* @param observer
* @return
*/
// public List removeObserve(Observer observer);
/**
* 发送消息/主题,让观察者动起来
*/
public void sendSubjectToObserver();
}
被观察者实现类
package com.example.test.observer;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: zhangpeng
* @Description:
* @Date: 2022/4/29
*/
public class SubjectImpl implements Subject{
List list;
@Override
public List addObserver(Observer observer) {
if(list == null){
list = new ArrayList<>();
}
list.add(observer);
return list;
}
@Override
public void sendSubjectToObserver() {
for(Observer observer : list){
observer.sendSubject();
}
}
}
注意里面的几个方法,后面对比监听者也用的到。
观察者抽象类:之所以是抽象类是方便扩展实现不同类型的观察者
package com.example.test.observer;
/**
* @Author: zhangpeng
* @Description:
* @Date: 2022/4/29
*/
public abstract class Observer {
public abstract void sendSubject();
}
观察者A实例
package com.example.test.observer;
/**
* @Author: zhangpeng
* @Description:
* @Date: 2022/4/29
*/
public class ObserverA extends Observer{
@Override
public void sendSubject() {
System.out.println("我是观察者A");
}
}
我们观察一下观察者,觉得只分成两部分,能不能做个扩展对应触发观察者逻辑的部分能不能拿出来,这样迄不是扩展性更强。
当然可以监听器,就是单独出来一个事件,观察者根据事件的创建直接出发逻辑,看起来好像是在监听一样,听到消息就要去报告一样.
以下是监听器的代码
监听器的事件源,它对应的是观察者的被观察者的一部分,包括注册,维护观察者/监听器列表等。
package com.example.test.monitor;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: zhangpeng
* @Description:
* @Date: 2022/4/29
* 对比观察者的的被观察者/主题。这个角色进行对比
*/
public class EventSource {
/**
* 监听器列表
*/
private List listeners;
/**
* 添加监听器
* @param myMonitor
* @return
*/
public List addMonitor(MyMonitor myMonitor){
if( listeners == null ){
listeners = new ArrayList<>();
}
listeners.add(myMonitor);
return listeners;
}
/**
* 移除监听器
* @return
*/
public List removeMonitor(){
if(listeners == null){
return listeners;
}
for (MyMonitor listener : listeners){
if(listeners.getClass().isInstance(DiguaMonitor.class)){
listeners.remove(listener);
}
if(listener.getClass().isInstance(QieziMonitor.class)){
listeners.remove(listener);
}
}
return listeners;
}
public void gotoListener(Event event){
for(MyMonitor listener : listeners){
listener.monitotToTudou(event);
}
}
}
事件,其实可以看作是一个抽象出来的监视对象,当监视对象创建出来就会,有对应的监视器采取相关的动作,这里我用的是,“地瓜,地瓜,我是土豆,我听到了!”,这种耳熟能详的暗号来做例子,地瓜可以监视土豆,是不是茄子也可以,这是当然的。
以下是监视器的代码:
package com.example.test.monitor;
/**
* @Author: zhangpeng
* @Description:
* @Date: 2022/4/29
*/
public class DiguaMonitor implements MyMonitor{
@Override
public void monitotToTudou(Event event) {
if(event.getType() == 1){
System.out.println("地瓜,地瓜,我是土豆,我听到了!");
}
}
}
那现在我们缺一个被监视的土豆对象,这个被监视的对象就是我们的Event事件
package com.example.test.monitor;
/**
* @Author: zhangpeng
* @Description:
* @Date: 2022/4/29
*/
public class Event {
/**
* 类型:1 代表地瓜是监听者要监听的事件 ,2 代表茄子是监听者且子要监听的时间
*/
private Integer type;
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
}
spring也是自带监视器,不管是注解@EventListener还是实现ApplicationListener接口,实际都是你去继承实现人家定的模式。
当然他们刚开始是有区别的,有的是后置处理器处理的,有的是直接接口的实现类,但最后的去处都是spring的多播放器然后再到applicationListeners管理雕鹰
这里面推荐一个小哥的专栏,我也是从这里对spring的两种监听器有了更深一步的了解。
涉及到spring的源码的spring监听器解析