Java设计模式-行为型设计模式-观察者模式

Java设计模式-行为型设计模式-观察者模式,第1张

Java设计模式-行为型设计模式-观察者模式

从这一专栏开始将学习设计模式,上课学习和自己总结归纳的笔记将总结出来供大家参考。
参考书籍:《设计模式就该这样学》

其他文章:

Java设计模式-UML类图Java设计模式-七大架构设计原则-开闭原则
Java设计模式-七大架构设计原则-依赖倒置原则Java设计模式-七大架构设计原则-单一职责原则
Java设计模式-七大架构设计原则-接口隔离原则Java设计模式-七大架构设计原则-最少知道原则(迪米特法则)
Java设计模式-七大架构设计原则-里氏替换原则和合成复用原则Java设计模式-创建型设计模式-简单工厂模式
Java设计模式-创建型设计模式-工厂方法模式(工厂模式)Java设计模式-创建型设计模式-抽象工厂模式
Java设计模式-创建型设计模式-建造者模式Java设计模式-创建型设计模式-原型模式
Java设计模式-创建型设计模式-单例模式Java设计模式-结构型设计模式-适配器模式
Java设计模式-行为型设计模式-观察者模式

文章目录
  • Java设计模式-行为型设计模式-观察者模式
    • 一、行为型设计模式
    • 二、观察者模式
      • 1.观察者模式定义
      • 2.观察者模式的角色
      • 3.观察者模式的特点
      • 4.观察者模式的类图
      • 5.观察者模式的通用写法
      • 6.观察者模式在Spring框架中的应用
        • Spring中观察者模式的四个角色
        • 1.环境搭建
          • 1.1创建配置类ExtConfig
          • 1.2创建MyApplicationListener实现ApplicationListener接口
          • 1.3测试代码和结果
        • 2.源码分析-ApplicationListener原理
          • 2.1ContextRefreshedEvent事件
          • 2.2IocTest事件
          • 2.3ContextClosedEvent事件

一、行为型设计模式

在GOF23种设计模式中,有三种类型的设计模式,分别是:创建型设计模式、结构型设计模式、行为型设计模式。

在GoF23种设计模式中属于行为型设计模式:

Chain of Responsibility ( 责任链模式 )、Command ( 命令模式 )、Interpreter ( 解释器模式 ) 、Iterator ( 迭代器模式 )、Mediator ( 中介者模式 ) 、Memento ( 备忘录模式 ) 、Observer ( 观察者模式 )、State ( 状态模式 ) 、Strategy ( 策略模式 )、TemplateMethod ( 模板方法 )、Visitor ( 访问者模式 )11种模式。

二、观察者模式 1.观察者模式定义

观察者模式(Observer Pattern):又叫做发布-订阅模式(Publish/Subscribe pattern)、模型-视图(Model/View pattern)。定义一种一对多的依赖关系,一个主题对象可以被多个观察值对象同时监听,使得每当主题对象状态变化时,所有依赖它的对象都会得到通知并被自动更新。

在GoF23种设计模式中属于行为型设计模式:

其中包括:Chain of Responsibility ( 责任链模式 )、Command ( 命令模式 )、Interpreter ( 解释器模式 ) 、Iterator ( 迭代器模式 )、Mediator ( 中介者模式 ) 、Memento ( 备忘录模式 ) 、Observer ( 观察者模式 )、State ( 状态模式 ) 、Strategy ( 策略模式 )、TemplateMethod ( 模板方法 )、Visitor ( 访问者模式 )11种模式。

2.观察者模式的角色

抽象主题(ISubject):指被观察的对象,一般是一个抽象类或者是接口,定义了增加、删除、通知观察者对象的方法。

具体主题(ConcreteSubject):具体被观察的对象,当其内部状态变化的时候,会通。已注册的观察者。

抽象观察者(IObserver):定义了响应通知的更新方法。

具体观察者(ConcreteObserver):当得到状态更新的通知时,会自动做出响应。

3.观察者模式的特点

优点:

观察者和被观察者是松耦合的,符合依赖倒置原则(高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象);

分离了观察者和被观察者,并且建立了一套触发机制,使得被观察者数据的变化可以响应到多个观察者上;

实现了一对多的通信机制,支持事件处理机制,支持兴趣分发机制,当被观察者触发事件时,只有感兴趣的观察者可以接收到通知。

缺点:

如果观察者的数量过多,则事件通知会耗费更多的时长;
事件通知呈线性关系,如果其中一个观察者处理事件卡壳,则会影响后续的观察者修改该事件;
如果观察者和被观察者之间存在循环依赖,则可能导致两者之间循环调用导致系统崩溃。

观察者模式的应用场景:

起床闹钟设置(如果一个人设置了一个闹钟,那么便会被闹钟提醒,那么闹钟就是被观察者,用户就是观察者);

朋友圈点赞提醒(微信朋友圈点赞之后,你就是观察者,微信的那条朋友圈就是被观察者);

网购APP商品降价通知推送(网购平台上,关注某个商品,当商品降价时,会收到通知)。

4.观察者模式的类图

5.观察者模式的通用写法
/**
 * 抽象观察者
 */
interface Observer{
    void response();
}

/**
 * 具体观察者A
 */
class ConcreteObserverA implements Observer{
    @Override
    public void response() {
        System.out.println("具体观察者A作出反应!");
    }
}

/**
 * 具体观察者B
 */
class ConcreteObserverB implements Observer{
    @Override
    public void response() {
        System.out.println("具体观察者B作出反应!");
    }
}

/**
 * 抽象主题(被观察者)
 */
abstract class Subject{
    protected List observers = new ArrayList<>();

    /**
     * 增加观察者方法
     * @param observer
     */
    public void add(Observer observer){
        observers.add(observer);
    }

    /**
     * 删除观察者方法
     * @param observer
     */
    public void remove(Observer observer){
        observers.remove(observer);
    }

    /**
     * 通知观察者方法
     */
    public abstract void notifyObserver();
}

/**
 * 具体目标(具体被观察者)
 */
class ConcreteSubject extends Subject{
    @Override
    public void notifyObserver() {
        System.out.println("具体目标发生改变!");
        System.out.println("----------------");
        for(Observer obs : observers){
            obs.response();
        }
    }
}

public class ObserverSimpleTest {
    public static void main(String[] args){
        Subject subject = new ConcreteSubject();
        Observer observerA = new ConcreteObserverA();
        Observer observerB = new ConcreteObserverB();
        subject.add(observerA);
        subject.add(observerB);
        subject.notifyObserver();
    }
}

6.观察者模式在Spring框架中的应用

观察者模式在Spring框架中的具体实现就是事件模型驱动开发

Spring中观察者模式的四个角色

1.事件(ApplicationEvent)

ApplicationEvent 是所有事件对象的父类,类似于被观察者要做的被观察的事情。

类似于上面通用写法中的:

用户可以通过继承ApplicationEvent,实现自定义事件。

下列描述了Spring提供的内置事件:

ContextRefreshedEvent:Spring容器刷新完成(所有bean都完成创建)的事件;

ContextClosedEvent:关闭Spring容器的时候的事件。

…等

2.事件发布(ApplicationEventPublisher/ApplicationContext)

ApplicationContext 是 Spring 中的核心容器,通过它的publishEvent()发布事件的通知给观察者(ApplicationListener)监听到(告诉观察者你需要观察哪个事件),因为事件创建好了不知道会不会被观察者观察到,所以会使用它。

3.事件监听(ApplicationListener)

ApplicationListener 事件监听器,也就是抽象观察者。继承自 jdk 的 EventListener,该类中只有一个方法 onApplicationEvent(),通过这个方法就是在事件执行的时候观察者要做的事情, 用户可以实现ApplicationListener接口进行事件监听(创建具体观察者)

4.事件多播器(ApplicationEventMulticaster)

ApplicationEventMulticaster 用于事件监听器的注册和事件的广播。等同于被观察者中的observers属性,监听器的注册、删除、把 Applicationcontext (被观察者)发布的事件广播给它的ApplicationListener(被观察者)列表(让他们进行链式调用)。

1.环境搭建 1.1创建配置类ExtConfig
@ComponentScan("com.wxr.ext")
@Configuration
public class ExtConfig {
 
}
1.2创建MyApplicationListener实现ApplicationListener接口

这就是用户自定义创建的具体观察者类

@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {

    /**
     * 当容器中发布此事件以后,该方法出发
     * 监听ApplicationEvent及下面的子事件
     * 根据ApplicationEvent的继承关系:
     * 例如:
	 *		ContextRefreshedEvent:容器刷新完成(所有bean都完成创建)会发布这个事件
     *      ContextClosedEvent:关闭容器的时候会发布这个事件
     * 步骤: 
     *      1.写一个监听器来监听某个事件(ApplicationEvent及其子类)
     *      2.把监听器加入到容器中
     *      3.只要容器中有相应类型的事件发布,我们就监听到这个事件
     * @param event
     */
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("收到事件:"+event);
    }
}

1.3测试代码和结果
public class IocTest {
    @Test
    public void test02(){
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(ExtConfig.class);
        //发布事件
        ioc.publishEvent(new ApplicationEvent(new String("我发布的事件")) {
        });
        System.out.println("ioc容器创建完成");
        ioc.close();
    }
}

2.源码分析-ApplicationListener原理

根据三.1的输出结果,我们按照先后顺序从ContextRefreshedEvent,IocTest$1,ContextClosedEvent进行分析

执行步骤:

1.向spring容器中注册事件多播器(ApplicationEventMulticaster)

2.向spring容器中注册事件监听器(ApplicationListener)

3.通过事件发布(ApplicationEventPublisher/ApplicationContext)的publishEvent()告诉监听器需要监听的是哪个事件

     3.1获取事件多播器(ApplicationEventMulticaster),通过它来遍历所有的事件监听器(ApplicationListener),并且调用他们的		   onApplicationEvent()进行事件监听

​	 3.2完成事件监听

2.1ContextRefreshedEvent事件

2.1.1创建IoC容器(调用AnnotationConfigApplicationContext的构造器)

public class IocTest {
    @Test
    public void test02(){
        //2.1.1.1走这里
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(ExtConfig.class);
        //发布事件      
        ioc.publishEvent(new ApplicationEvent(new String("我发布的事件")) {
        });
        System.out.println("ioc容器创建完成");
        ioc.close();
    }
}


//AnnotationConfigApplicationContext的构造器
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
   this();
   register(annotatedClasses);
    //2.1.1.1走这里
   refresh();
}

2.1.1.1调用AbstractApplicationContext.refresh()刷新容器

/**
 *这是AbstractApplicationContext.refresh()
 */
@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			
			prepareRefresh();

			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			prepareBeanFactory(beanFactory);

			try {
				postProcessBeanFactory(beanFactory);

                //执行BeanFactoryPostProcessors
				invokeBeanFactoryPostProcessors(beanFactory);

                //注册bean的后置处理器
				registerBeanPostProcessors(beanFactory);
                  
                // 初始化事件的多播器(派发器),在2.1.1.1.1.1.1会提到
				initApplicationEventMulticaster();
                
                
                // 注册所有的监听器,从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中
				registerListeners();
                
                           
                //调用本类的finishBeanFactoryInitialization(beanFactory)完成BeanFactory的初始化工作
                //实例化剩下的单实例Bean               
				finishBeanFactoryInitialization(beanFactory);
                
                //调用本类的finishRefresh(),容器刷新完成
                //2.1.1.1.1走这里
				finishRefresh();
               
 			}
    }

2.1.1.1.1调用AbstractApplicationContext.finishRefresh()完成容器刷新

protected void finishRefresh() {
   // Initialize lifecycle processor for this context.
   initLifecycleProcessor();

   // Propagate refresh to lifecycle processor first.
   getLifecycleProcessor().onRefresh();

   //发布事件ContextRefreshedEvent刚刚好2.1ContextRefreshedEvent是一样的
   //调用本类下的publishEvent(new ContextRefreshedEvent(this))
    //2.1.1.1.1.1走这里
   publishEvent(new ContextRefreshedEvent(this));

   // Participate in LiveBeansView MBean, if active.
   LiveBeansView.registerApplicationContext(this);
}

2.1.1.1.1.1调用AbstractApplicationContext. publishEvent(new ContextRefreshedEvent(this)) 开始进行ContextRefreshedEvent事件发布

@Override
public void publishEvent(ApplicationEvent event) {
   publishEvent(event, null);
}

protected void publishEvent(Object event, ResolvableType eventType) {
		Assert.notNull(event, "Event must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Publishing event in " + getDisplayName() + ": " + event);
		}

		// Decorate event as an ApplicationEvent if necessary
		ApplicationEvent applicationEvent;
		if (event instanceof ApplicationEvent) {
			applicationEvent = (ApplicationEvent) event;
		}
		else {
			applicationEvent = new PayloadApplicationEvent<Object>(this, event);
			if (eventType == null) {
				eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
			}
		}

		// Multicast right now if possible - or lazily once the multicaster is initialized
		if (this.earlyApplicationEvents != null) {
			this.earlyApplicationEvents.add(applicationEvent);
		}
		else {
            //1.获取事件的多播器(派发器):getApplicationEventMulticaster() 2.1.1.1.1.1.1走这里
            //2.派发事件:multicastEvent(applicationEvent, eventType)2.1.1.1.1.1.2走这里
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		// Publish event via parent context as well...
		if (this.parent != null) {
			if (this.parent instanceof AbstractApplicationContext) {
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				this.parent.publishEvent(event);
			}
		}
	}

2.1.1.1.1.1.1调用getApplicationEventMulticaster()获取事件的多播器(派发器)

ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
   if (this.applicationEventMulticaster == null) {
      throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
            "call 'refresh' before multicasting events via the context: " + this);
   }
   return this.applicationEventMulticaster;
}

获取方法在refresh()的initApplicationEventMulticaster()中

protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    //判断在beanFactory中是否有id="applicationEventMulticaster"的组件
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
       //如果有就直接获取
      this.applicationEventMulticaster =        
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
      if (logger.isDebugEnabled()) {
         logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
      }
   }
   else {
       //如果没有那么就自己创建一个新的id="applicationEventMulticaster"并注册到容器中
       //我们可以再其他组件要派发事件的时候,自动注入这个applicationEventMulticaster
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
      if (logger.isDebugEnabled()) {
         logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
               APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
               "': using default [" + this.applicationEventMulticaster + "]");
      }
   }
}

2.1.1.1.1.1.2调用SimpleApplicationEventMulticaster. multicastEvent(final ApplicationEvent event, ResolvableType eventType) 进行派发事件

@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    //拿到所有的ApplicationListener挨个遍历
   for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      Executor executor = getTaskExecutor();
       //如果有异步执行的功能,那么通过多线程的方式异步派发invokeListener(listener, event);
      if (executor != null) {
         executor.execute(new Runnable() {
            @Override
            public void run() {
               invokeListener(listener, event);
            }
         });
      }
      else {
          //否则用同步的方式直接调用本类下的invokeListener(listener, event);
          //2.1.1.1.1.1.2.1走这里
         invokeListener(listener, event);
      }
   }
}

2.1.1.1.1.1.2.1调用SimpleApplicationEventMulticaster.invokeListener(ApplicationListener listener, ApplicationEvent event)

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
   ErrorHandler errorHandler = getErrorHandler();
   if (errorHandler != null) {
      try {
         doInvokeListener(listener, event);
      }
      catch (Throwable err) {
         errorHandler.handleError(err);
      }
   }
   else {
       //这次走这里
      doInvokeListener(listener, event);
   }
}


//再次调用本类下的doInvokeListener(ApplicationListener listener, ApplicationEvent event)
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
            //2.1.1.1.1.1.2.1.1
            //走这个方法直接回调到我们自己写的MyApplicationListener. onApplicationEvent(ApplicationEvent event) 
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || msg.startsWith(event.getClass().getName())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				Log logger = LogFactory.getLog(getClass());
				if (logger.isDebugEnabled()) {
					logger.debug("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

2.1.1.1.1.1.2.1.1回到我们自己写的MyApplicationListener. onApplicationEvent(ApplicationEvent event)完成事件发布

@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("收到事件:"+event);
    }
}
2.2IocTest$1事件

2.2.1调用自己写的发布时间方法ioc.publishEvent(new ApplicationEvent(new String(“我发布的事件”)) {});

public class IocTest {
    @Test
    public void test02(){
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(ExtConfig.class);
        //2.2.1.1走这里       
        ioc.publishEvent(new ApplicationEvent(new String("我发布的事件")) {
        });
        System.out.println("ioc容器创建完成");
        ioc.close();
    }
}

2.2.1.1直接调用AbstractApplicationContext. publishEvent(new ContextRefreshedEvent(this)) 开始进行ContextRefreshedEvent事件发布

@Override
public void publishEvent(ApplicationEvent event) {
   publishEvent(event, null);
}

protected void publishEvent(Object event, ResolvableType eventType) {
		Assert.notNull(event, "Event must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Publishing event in " + getDisplayName() + ": " + event);
		}

		// Decorate event as an ApplicationEvent if necessary
		ApplicationEvent applicationEvent;
		if (event instanceof ApplicationEvent) {
			applicationEvent = (ApplicationEvent) event;
		}
		else {
			applicationEvent = new PayloadApplicationEvent<Object>(this, event);
			if (eventType == null) {
				eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
			}
		}

		// Multicast right now if possible - or lazily once the multicaster is initialized
		if (this.earlyApplicationEvents != null) {
			this.earlyApplicationEvents.add(applicationEvent);
		}
		else {
            //1.获取事件的多播器(派发器):getApplicationEventMulticaster()
            //2.派发事件:multicastEvent(applicationEvent, eventType),这次走这里
			getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}

		// Publish event via parent context as well...
		if (this.parent != null) {
			if (this.parent instanceof AbstractApplicationContext) {
				((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
			}
			else {
				this.parent.publishEvent(event);
			}
		}
	}

2.2.1.1后面的逻辑和2.1.1.1.1.1.2之后一样了这里就不赘述了

2.3ContextClosedEvent事件

2.3.1调用ioc.close()

public class IocTest {
    @Test
    public void test02(){
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(ExtConfig.class);
        //发布事件 
        ioc.publishEvent(new ApplicationEvent(new String("我发布的事件")) {
        });   
        System.out.println("ioc容器创建完成");
        //2.3.1.1走这里
        ioc.close();
    }
}

2.3.1.1调用AbstractApplicationContext.close()关闭容器

@Override
public void close() {
   synchronized (this.startupShutdownMonitor) {
       //这次走这里
      doClose();
      // If we registered a JVM shutdown hook, we don't need it anymore now:
      // We've already explicitly closed the context.
      if (this.shutdownHook != null) {
         try {
            Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
         }
         catch (IllegalStateException ex) {
            // ignore - VM is already shutting down
         }
      }
   }
}
protected void doClose() {
     //多余代码省略
      try {
         //发布ContextClosedEvent事件
          //2.3.1.1.1走这里
         publishEvent(new ContextClosedEvent(this));
      }
      //多余代码省略
}

2.3.1.1.1调用AbstractApplicationContext.publishEvent(ApplicationEvent event)发布ContextClosedEvent事件

2.3.1.1.1.1后面的逻辑和2.1.1.1.1.1.2之后一样了这里就不赘述了

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/904409.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-15
下一篇 2022-05-15

发表评论

登录后才能评论

评论列表(0条)

保存