观察者模式

270 阅读3分钟

观察者设计模式

可以用订阅和发布来理解观察者模式,
为什么呢?因为监听器这个名词听起来是一个主动的,可实际监听器是一个被动的玩意
比如我们事件源发布一个事件,然后监听器订阅了这个事件就能做出动作。
里面涉及到三个对象,事件源,事件、监听器

特点:

  • 持有监听的观察者的引用
  • 支持增加和删除观察者
  • 主题状态改变,通知观察者

与发布订阅模式的区别

  • 观察者模式

    屏幕快照 2019-10-22 20.29.06

  • 发布订阅模式

屏幕快照 2019-10-22 20.29.25

基本的观察者模式

屏幕快照 2019-10-22 20.45.40

JDK实现的观察者模式

  • JDK实现的观察者模式主要通过两个类,分别是

    • java.util.Observable:被观察者,主要定义了addObserver、deleteObserver、notifyObservers以及setChanged方法(如果被观察者的状态发生了改变,需要通知观察者需要先调用setChanged方法改变标识,然后调用notifyObservers方法)

      public void notifyObservers(Object arg) {
              /*
               * a temporary array buffer, used as a snapshot of the state of
               * current Observers.
               */
              Object[] arrLocal;
      
              synchronized (this) {
                
                  if (!changed)
                      return;
                  arrLocal = obs.toArray();
                  clearChanged();
              }
      
              for (int i = arrLocal.length-1; i>=0; i--)
                  ((Observer)arrLocal[i]).update(this, arg);
          }
      
    • java.util.Observer:观察者需要实现的接口,只有一个void update(Observable o, Object arg);方法,用来执行变更。

Spring实现的观察者模式

  • Spring实现的观察者模式的方式是通过events机制

    • ApplicationEvent:事件的抽象类,所有自定义的事件需要继承ApplicationEvent,并重写其构造方法,构造方法中可以传入自定义的数据信息(EventSource)

      public class AfterAuditEvent extends ApplicationEvent {
          /**
           * Create a new ApplicationEvent.
           *
           * @param source the object on which the event initially occurred (never {@code null})
           */
          public AfterAuditEvent(AfterAuditInfo source) {
              super(source);
          }
      }
      
    • ApplicationListener:观察者需要实现的接口,使用范型指定监听指定的ApplicationEvent

      public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
      
      	/**
      	 * Handle an application event.
      	 * @param event the event to respond to
      	 */
      	void onApplicationEvent(E event);
      
      }
      
      
    • SmartApplicationListener:继承了ApplicationListener的接口,并添加了监听指定event事件和eventSource,继承了Ordered,支持优先性排序

      public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
      
      	/**
      	 * Determine whether this listener actually supports the given event type.
      	 */
      	boolean supportsEventType(Class<? extends ApplicationEvent> eventType);
      
      	/**
      	 * Determine whether this listener actually supports the given source type.
      	 */
      	boolean supportsSourceType(@Nullable Class<?> sourceType);
      
      }
      
    • 发送事件:在类中注入ApplicationContext类(Spring应用上下文,然后调用publishEvent方法)

      @Component
      public class Test {
      
          private final ApplicationContext context;
      
          public Test(ApplicationContext context) {
              this.context = context;
          }
      
          public void doCustomer(BidRequirementParam param, LoginUser user) {
                  context.publishEvent(new AfterAuditEvent(new AfterAuditInfo(user, param)));
              }
          }
      }
      
      

Spring中内置的Events

事件通过org.springframework.context.ApplicationEvent实例来表示。这个抽象类继承扩展了java.util.EventObject,可以使用EventObject中的getSource方法,我们可以很容易地获得所发生的给定事件的对象。这里,事件存在两种类型

  1. 与应用程序上下文相关联

    所有这种类型的事件都继承自org.springframework.context.event.ApplicationContextEvent类。它们应用于由org.springframework.context.ApplicationContext引发的事件(其构造函数传入的是ApplicationContext类型的参数)。这样,我们就可以直接通过应用程序上下文的生命周期来得到所发生的事件:ContextStartedEvent在上下文启动时被启动,当它停止时启动ContextStoppedEvent,当上下文被刷新时产生ContextRefreshedEvent,最后在上下文关闭时产生ContextClosedEvent

  2. 与request 请求相关联

    org.springframework.web.context.support.RequestHandledEvent实例来表示,当在ApplicationContext中处理请求时,它们被引发。

    Spring如何将事件分配给专门的监听器?

这个过程由事件广播器来实现,由org.springframework.context.event.ApplicationEventMulticaster接口的实现表示。此接口定义了3种方法

  1. addApplicationListener() 添加新的监听器**:定义了两种方法来添加新的监听器:addApplicationListener(ApplicationListener<?> listener)addApplicationListenerBean(String listenerBeanName)。当监听器对象已知时,可以应用第一个。如果使用第二个,我们需要将bean name 得到listener对象(依赖查找DL),然后再将其添加到listener列表中
  2. removeApplicationListenerBean(String listenerBeanName) 删除监听器:添加方法一样,我们可以通过传递对象来删除一个监听器(**removeApplicationListener(ApplicationListener<?> listener)**或通过传递bean名称。第三种方法,**removeAllListeners()**用来删除所有已注册的监听器
  3. multicastEvent(ApplicationEvent event) 将事件发送到已注册的监听器