转载请联系程序新视野公众号。前言不管你在实践中实现过观察者模式还是监听者模式,你肯定间接使用过。比如Spring的事件机制,想必大多数人都用过,只是没注意罢了。今天的文章主要围绕观察者模式、倾听者模式,以及它们之间的关系展开。不仅通过实例介绍了它们的使用,还讲述了Spring事件机制对观察者模式的实践。监听器模式和观察者模式怎么看起来一样呢?下面说说设计模式为什么要用监控模式。直接调用不好吗?下面说说设计模式的好处。设计模式(Designpattern)是对代码设计经验的总结,被反复使用,为大多数人所熟知,分类归类。设计模式用于可重用的代码,使代码更容易被他人理解,并保证代码的可靠性。同时,采用设计模式后,代码可以达到低耦合、低依赖的效果。也就是说,即使没有设计模式,也可以实现直接hardcoding。但如果考虑代码耦合、依赖、可扩展性等问题,设计模式是更好的选择。比如观察者模式可以达到解耦、异步等效果。观察者模式的定义观察者模式定义了对象之间一对多的依赖关系,即一个主体对应多个观察者。当一个主题对象改变状态时,它的所有依赖者(观察者)都会被自动通知和更新。比如用户订阅了一个订阅号或者公众号,当有新消息发送时,会发送给所有订阅者。观察者模式解决了对象与对象之间的依赖关系。当多个对象依赖于一个对象的关系,一个主体对象改变状态时,需要通知所有的观察者对象。监听器模式并不是一种新的设计模式,它是观察者模式在特定场景下的改造和应用。通常,当观察者模式的主题通知观察者时,通知不包含任何信息。如果在这个过程中携带了一些其他的信息,那么主题本身就变成了事件源,携带信息的封装类就变成了事件。此时观察者模式升级为监听者。侦听器模式是观察者模式的另一种形式。观察者模式示例首先我们看一下观察者模式的代码实现。可以直接使用JDK自带的Observer,也可以自定义相应的API。仅仅从JDK自带的观察者模式的API中,我们也可以看出这种设计模式的重量(虽然在Java中被抛弃了)。我们这里使用自定义的相关类,主要包括两个对象,subject和observer。首先定义一个topic对应的接口Subject:publicinterfaceSubject{/***注册定义*/voidregisterObserver(Observerobserver);/***发送通知*/voidnotifyObservers(Objectmsg);}subject接口中定义了两个方法,一个用于注册观察员,一种用于发送通知。定义本主题的具体实现类ConcreteSubject:publicclassConcreteSubjectimplementsSubject{/***observercollection*/privateListobservers=newArrayList<>();@OverridepublicvoidregisterObserver(Observerobserver){//添加订阅关系observers.add(observer);}@OverridepublicvoidnotifyObservers(Objectmsg){//Notifysubscribersfor(Observerobserver:observers){observer.update(msg);}}}观察者的集合存放在实现类中,从而实现了主体与观察者的关系-对多关系。创建一个观察者接口Observer,方便管理:publicinterfaceObserver{//处理业务逻辑voidupdate(Objectmsg);}定义观察者接口的具体实现类ConcreteObserver:publicclassConcreteObserverimplementsObserver{@Overridepublicvoidupdate(Objectmsg){//业务逻辑实现System.out。println("ConcreteObserver收到主题消息:"+msg);}}在实现类中,打印一行消息。当然在实际中,可以通过匿名类的形式来创建这个实现类,这样在registerObserver的时候就定义了具体的匿名类。我们来测试一下:publicclassConcreteObserverimplementsObserver{@Overridepublicvoidupdate(Objectmsg){//业务逻辑实现System.out.println("ConcreteObserverreceivedthetopicmessage:"+msg);}}执行程序,打印结果:ConcreteObserverreceivedthetopicmessage消息:来自Subject的消息表示可以正常接收到该Subject发布的消息。在上面的实现中,可以看出在减少依赖的同时,也达到了解耦的效果。每个观察者不需要知道发布者处理什么业务逻辑,也不依赖于发布者的业务模型,只关心自己的逻辑处理。监听器模式实例监听器模式通常包括三个角色:事件源、事件对象、事件监听器。如果在不改变业务逻辑的情况下改变观察者模式下的类名和方法,我们来看看效果。比如把Observer的名字改成Listener,把它的update方法改成onClick();将Subject的实现类ConcreteSubject改为ListenerSupport,将registerObserver的方法改为addListener...定义一个事件对象Event,传递事件信息:this.type=type;}//省略getter/setter}原topic的订阅对象Observer改名为Listener后,就变成了一个监听器:publicinterfaceListener{voidonClick(Eventevent);}为监听器提供一个实现类。当然在实际中也可以使用匿名类创建:publicclassListenerAimplementsListener{@OverridepublicvoidonClick(Eventevent){System.out.println("触发事件,type:"+event.getType()+",data:"+event.getData());}}原始主题ConcreteSubject成为针对ListenerSupport的事件管理器:publicclassListenerSupport{privateListlisteners=newArrayList<>();publicvoidaddListener(Listenerlistener){listeners.add(listener);}publicvoidtriggerEvent(Eventevent){for(Listenerlistener:listeners){listener.onClick(event);}}}对应的测试代码:publicclassEventTest{publicstaticvoidmain(String[]args){Listenerlistener=newListenerA();ListenerSupportlistenerSupport=newListenerSupport();listenerSupport.addListener(listener);listenerSupport.triggerEvent(newEvent("dataA","typeA"));}}执行程序,打印信息如下:触发事件,类型:typeA,data:dataA通过上面的对比代码可以看出,即使业务逻辑不变,改名后的观察者模式变成了监听者模式,他们的对比关系是:事件源vs.ConcreteSubject(主题),事件对象比较更新方法的对象和事件侦听器与ConcreteObserver(订阅者)。这也再次证明了所谓“监听者模式是观察者模式的另一种形式”。观察者模式和监听者模式对比用一张图来对比观察者模式和监听者模式的关系和区别:通过对比可以看出监听者模式的优势:在很多场景下,通知自带一些必要的信息,其他信息很少,而事件Event可以封装这些信息,使其具有多态特性。每个事件对象可以包含不同的信息。从这个层面来看,事件监听器模式是观察者模式的进一步抽象。最佳实践观察者模式在Spring中的经典应用就是Spring事件驱动模型,它是基于观察者模式实现的,也是项目中最常见的事件监听器。Spring中的观察者模式包括四种角色:事件、事件监听器、事件源、事件管理。事件:ApplicationEvent是所有事件对象的父类。ApplicationEvent继承自jdk的EventObject,所有事件都需要继承ApplicationEvent,通过source获取事件源。Spring提供了很多内置事件,例如:ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent、RequestHandledEvent。事件监听器:ApplicationListener,即观察者,继承自jdk的EventListener。该类中只有一个方法onApplicationEvent,当监听到的事件发生时就会执行。事件源:ApplicationContext。ApplicationContext是Spring的核心容器。在事件监听中,ApplicationContext可以作为事件的发布者,即事件源。因为ApplicationContext继承自ApplicationEventPublisher。事件发布的方法在ApplicationEventPublisher中定义:publishEvent(Objectevent)。事件管理:ApplicationEventMulticaster,用于事件监听器注册和事件广播。监听器的注册是通过它实现的,它的作用是将Applicationcontext发布的Event广播到它的监听器列表中。总结通过这篇文章,我们知道了监听者模式的本质是观察者模式。首先,将回调函数注册到被观察对象。当被观察对象发生变化时,通过回调函数通知观察者/监听者。Spring中的事件管理也是基于观察者模式实现的,是比较经典的案例。