目录
1.什么是监听者模式
2.监听者模式的组成(成员)
3.代码实现
4.思考
监听者模式在现实中无处不在,举个常见的例子,我们经常在电影片段中看到,当信号侦察兵接收到上级下发的某个指令信号,会立即执行相应动作.在古代,亦有烽火台,当烽火台被点燃时,远处哨兵观察到烟雾后会立刻通知士兵开始防御外敌... 类似这种收到某个"信号"后立即做出相应反馈的,在编程领域称之为监听者模式,这么说比较笼统,可能比较容易与观察者模式混淆,下面详细介绍下监听者模式.
监听者模式由事件源,事件对象,事件监听器三者共同构成.
事件源:被监听的事件本身,也就是可以触发监听器的某件事件,对应上面例子里的烽火台被点燃这个事件.
事件对象:事件对象里面存放了对事件源的引用,可以通过事件对象来获取事件源,是对事件源的包装.
事件监听器:定义事件发生后的动作,比如烽火台被点然后,要立即通知士兵防御.监听器里的具体逻辑由开发来实现.
单看上面的介绍可能比较空洞,甚至难以理解,作为程序猿还是代码来得更直接.
先上一个低配版:
场景:以我喜欢的一款游戏吃鸡为例,我特别喜欢舔空投,几乎每把都是空投之王,我喜欢顶配的感觉,当然也经常为此送命...
游戏中我一旦看到有人放信号枪,就会过去舔空投,下面用代码来实现下...
事件源:
public class SignalSource {
private SignalListener signalListener;
public void signal(){
System.out.println("打响了信号枪...");
if (signalListener!=null){
signalListener.doGetAirDrop(new Signal(this));
}
}
public SignalSource(SignalListener signalListener) {
this.signalListener = signalListener;
}
}
事件对象:
public class Signal {
private SignalSource signalSource;
public SignalSource getSignalSource() {
return signalSource;
}
public void setSignalSource(SignalSource signalSource) {
this.signalSource = signalSource;
}
public Signal(SignalSource signalSource) {
this.signalSource = signalSource;
}
}
监听器:
public interface SignalListener {
void doGetAirDrop(Signal signal);
}
测试:
public class Client {
public static void main(String[] args) {
SignalSource signalSource = new SignalSource((s)->{
System.out.println("看到有人在打信号枪,我要去舔空投了...");
});
signalSource.signal();
}
}
结果:
可以看出,当事件源被触发后,监听器里的逻辑被执行了. 也就是打响了信号枪之后,我开始去舔空投了.以上便是监听者模式的简单实现,看到这里,你是否跟我有同样的疑问,且继续往下看.
为什么要存在一个Signal(事件对象)?直接在事件源里触发监听器里的逻辑不就好了吗?要它有卵子用???
假如我把Signal(事件对象)去掉后,这特么不就变成了观察者模式了???
存在必有意义,既然23种设计模式里把观察者模式和监听者模式归为不同的设计模式,那必定有它的原因.
为了解决这个疑问,不妨先思考下,如果事件源不是打响信号枪,而是有人向投掷了一枚手雷呢?那此时要执行的动作应该是迅速卧倒或躲避,而非去舔空投. 在实际业务中,需要监听的事件源往往是多种多样的,针对不同的事件源需要有不同的监听器来执行后续操作,此时如果没有事件对象,就会像观察者模式一样,一旦事件源触发,所有监听事件都会被触发,这显然不合理,别人放个信号枪我还要卧倒或者躲避???
上面的代码似乎不能很好的体现这一点,但可以帮我们更好的理解监听者模式,天下大事,必做于易.
下面我写一个比较规范的监听者模式,继承自JDK的标准库的实现,在实际开发中和Spring源码中多采用这种方式:
同样的我还以上面的场景为例,分别模拟监听信号枪和手雷等事件:
事件源:
public class EventSource {
private List listenerList = new ArrayList<>();
public void fireEvent(EventObject event) {
listenerList.parallelStream()
.distinct()
.collect(Collectors.toList())
.forEach(l -> l.invoke(event));
}
public void addListener(Listener listener) {
if (listener != null) {
listenerList.add(listener);
}
}
public void removeListener(Listener listener) {
if (listener != null) {
listenerList.remove(listener);
}
}
}
事件对象:
//继承自Java.util.EventObject
public class Event extends EventObject {
private Object source;
private Integer state;
public Event(Object source) {
super(source);
}
@Override
public Object getSource() {
return source;
}
public void setSource(Object source) {
this.source = source;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
}
监听器:
//继承自java.util.EventListener
public interface Listener extends EventListener {
void invoke(EventObject event);
}
监听器实现类:
//针对打信号枪事件的监听
public class SignalListener implements Listener {
@Override
public void invoke(EventObject eventObject) {
Event event = (Event)eventObject;
if (Objects.equals(event.getState(),StateEnum.SIGNAL.getState())){
System.out.println("有人打信号枪了,我要去舔空投...");
}
}
}
//针对扔手雷事件的监听
public class BoomListener implements Listener {
@Override
public void invoke(EventObject eventObject) {
Event event = (Event)eventObject;
if (Objects.equals(event.getState(),StateEnum.BOOM.getState())){
System.out.println("有人扔手雷了,我要卧倒或者躲避...");
}
}
}
状态管理枚举类:
public enum StateEnum {
SIGNAL(1),
BOOM(2)
;
private Integer state;
StateEnum(Integer state) {
this.state = state;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
}
测试类:
public class Client {
public static void main(String[] args) {
EventSource eventSource = new EventSource();
SignalListener signalListener = new SignalListener();
BoomListener boomListener = new BoomListener();
eventSource.addListener(signalListener);
eventSource.addListener(boomListener);
Event event = new Event(eventSource);
event.setState(StateEnum.SIGNAL.getState());
eventSource.fireEvent(event);
event.setState(StateEnum.BOOM.getState());
eventSource.fireEvent(event);
}
}
效果:
可以通过具体的事件状态来实现对指定事件的监听,也可以通过事件源的addListener和removeListener来实现对监听器的热拔插,做到我想监听什么事件,就监听什么事件,不想监听的事件就不监听,由此也可以看出来,监听器模式似乎在功能上比观察者模式更灵活,但实现难度和复杂度要高于观察者模式,总之各有适用场景,灵活运用即可.
如果看完这篇你仍对监听者模式和观察者模式不够清楚,也不能很好的对应场景下使用对应的设计模式,没关系,可以参考我在下篇中详解监听者模式和观察者模式.