spring源码设计模式分析(四)-观察者模式

简介: spring源码设计模式分析(四)-观察者模式

观察者模式


在Spring里面用的就是事件监听,用事件监听的方式来扩展了观察者模式,理解了观察者模式就理解了顺序编程和逆向编程。

在我们解决某个问题的时候:请求方法1,会依赖请求方法2的结果,同时请求方法2,会依赖请求方法3的结果,这叫做顺序依赖。写程序的时候也是从上往下调,一直返回结果。依赖:就是自己解决不了这个问题,需要依赖另一个方法来帮解决这个问题

也可以逆序依赖,方法3依赖方法2的响应结果,方法2依赖方法1的响应结果,依赖产生行为后的一个状态[消息,事件],简称回调,类似js,jq中的事件监听器的模式。

实现方式:1、事件:观察者模式:这里有目标,和观察者,观察者观察目标,再进行响应。比如:老师讲课,学生听课就是典型的观察者模式。代码如下:

提供一个接口:

  1. package com.weizhaoyang.observer;

  2. public interface Observer {
  3.    /**
  4.     * 执行动作
  5.     */
  6.    public void  OnAction();
  7. }

提供一个目标类:

  1. package com.weizhaoyang.observer;

  2. import java.util.ArrayList;
  3. import java.util.List;

  4. /**
  5. * 创建目标对象(老师)
  6. */
  7. public class Subject {
  8.     //依赖观察者(学生)
  9.    List<Observer> studentObservers=new ArrayList<Observer>();
  10.    //添加观察者
  11.    public void addObserver(Observer observer){
  12.        studentObservers.add(observer);
  13.    }
  14.    //删除观察者
  15.    public void removeObserver(Observer observer){
  16.        studentObservers.remove(observer);
  17.    }
  18.    /**
  19.     * 产生一个行为
  20.     * 逆向
  21.     */
  22.    public void  action(){
  23.        System.out.println("老师开始上课了");
  24.        //通知所有的学生来进行响应,这种模式称之为推
  25.        if (studentObservers != null && studentObservers.size() > 0){
  26.            for(Observer observer:studentObservers){
  27.                new Thread(){
  28.                    @Override
  29.                    public void run() {
  30.                       observer.OnAction();
  31.                    }
  32.                }.start();

  33.            }
  34.        }
  35.    }

  36. }

提供一个观察者:

  1. package com.weizhaoyang.observer;

  2. public class StudentObserver implements Observer {
  3.    @Override
  4.    public void OnAction() {
  5.        System.out.println("学生收到通知,要开始上课了");
  6.    }
  7. }

测试的类如下:

  1. package com.weizhaoyang.observer;

  2. public class ObserverTest  {
  3.    public static void main(String[] args) {
  4.        Observer observer=new StudentObserver();
  5.        Subject  subject=new Subject();
  6.        subject.addObserver(observer);
  7.        subject.action();
  8.    }
  9. }

运行的结果如下:上面的异步通知可以称之为事件。类似消息队列。

每一个产生行为之后的就称之为消息。如果不想要去立刻发出消息的话,可以把这四个行为放到缓存里面。

  1. package com.weizhaoyang.observer;

  2. import java.util.ArrayList;
  3. import java.util.List;

  4. /**
  5. * 创建目标对象(老师)
  6. */
  7. public class Subject {
  8.     //依赖观察者(学生)
  9.    List<Observer> studentObservers=new ArrayList<Observer>();
  10.    //消息
  11.    List<String>MessageList=new ArrayList<String>();
  12.    //添加观察者
  13.    public void addObserver(Observer observer){
  14.        studentObservers.add(observer);
  15.    }
  16.    //删除观察者
  17.    public void removeObserver(Observer observer){
  18.        studentObservers.remove(observer);
  19.    }
  20.    /**
  21.     * 产生一个行为
  22.     * 逆向
  23.     */
  24.    public void  action(){
  25.        System.out.println("老师开始上课了");
  26.        MessageList.add("action1");
  27.        //通知所有的学生来进行响应
  28.        if (studentObservers != null && studentObservers.size() > 0){
  29.            for(Observer observer:studentObservers){
  30.                new Thread(){
  31.                    @Override
  32.                    public void run() {
  33.                       observer.OnAction();
  34.                    }
  35.                }.start();
  36.            }
  37.        }
  38.    }
  39.    public void  action1(){
  40.        System.out.println("老师开始上课了");
  41.        MessageList.add("action2");
  42.        //通知所有的学生来进行响应
  43.        if (studentObservers != null && studentObservers.size() > 0){
  44.            for(Observer observer:studentObservers){
  45.                new Thread(){
  46.                    @Override
  47.                    public void run() {
  48.                        observer.OnAction();
  49.                    }
  50.                }.start();
  51.            }
  52.        }
  53.    }
  54.    public void  action2(){
  55.        System.out.println("老师开始上课了");
  56.        MessageList.add("action3");
  57.        //通知所有的学生来进行响应
  58.        if (studentObservers != null && studentObservers.size() > 0){
  59.            for(Observer observer:studentObservers){
  60.                new Thread(){
  61.                    @Override
  62.                    public void run() {
  63.                        observer.OnAction();
  64.                    }
  65.                }.start();
  66.            }
  67.        }
  68.    }
  69.    public void  action3(){
  70.        System.out.println("老师开始上课了");
  71.        //消息
  72.        MessageList.add("action4");
  73.        //通知所有的学生来进行响应
  74.        if (studentObservers != null && studentObservers.size() > 0){
  75.            for(Observer observer:studentObservers){
  76.                new Thread(){
  77.                    @Override
  78.                    public void run() {
  79.                        observer.OnAction();
  80.                    }
  81.                }.start();
  82.            }
  83.        }
  84.    }
  85. }

上面的代码我们可以用通知统一的通知上面的四个消息。这时不依赖动作的行为,而是依赖消息队列  MessageList。而kafka,rabbitmq这些消息队列只是封装 了暴漏出接口给我们用而已。可以把上面的代码再次的改造,把消息放入到缓存里面,不是立马产生消息,开启一个定时轮询器,用动态线程轮询的方式去消息,而这种模式称之为拉模型。如果线程很好资源的话,可以用线程池。

  1. package com.weizhaoyang.observer;

  2. import java.util.ArrayList;
  3. import java.util.List;

  4. /**
  5. * 创建目标对象(老师)
  6. */
  7. public class Subject {
  8.     //依赖观察者(学生)
  9.    List<Observer> studentObservers=new ArrayList<Observer>();
  10.    //消息
  11.    List<String>MessageList=new ArrayList<String>();
  12.    //添加观察者
  13.    public void addObserver(Observer observer){
  14.        studentObservers.add(observer);
  15.    }
  16.    //删除观察者
  17.    public void removeObserver(Observer observer){
  18.        studentObservers.remove(observer);
  19.    }
  20.    /**
  21.     * 产生一个行为
  22.     * 逆向
  23.     */
  24.    public void  action(){
  25.        System.out.println("老师开始上课了");
  26.        MessageList.add("action1");
  27.        //通知所有的学生来进行响应

  28.    }
  29.    public void  action1(){
  30.        System.out.println("老师开始上课了");
  31.        MessageList.add("action2");
  32.        //通知所有的学生来进行响应

  33.    }
  34.    public void  action2(){
  35.        System.out.println("老师开始上课了");
  36.        MessageList.add("action3");
  37.        //通知所有的学生来进行响应

  38.    }
  39.    public void  action3(){
  40.        System.out.println("老师开始上课了");
  41.        MessageList.add("action4");
  42.        //通知所有的学生来进行响应

  43.    }
  44. }

推消息是主动的推消息,拉是主动的从消息队列里面去拉取消息。这就是从观察者设计模式延申到消息队列一些知识点。下面的是最简单的消息队列:每产生一个动作,就发送一条消息。

如果不直接消费的话,就可以从messgeList里面去拉取感兴趣的消息,在spring中用的是事件的方式,代码改造如下:

1、首先加一个事件:

  1. package com.weizhaoyang.observer;

  2. /**
  3. * 事件对象
  4. */
  5. public class MyEvent {
  6.    //目标对象
  7.    public Object target;
  8.    //其他参数
  9.    private String name;

  10.    public MyEvent(Object target, String name) {
  11.        this.target = target;
  12.        this.name = name;
  13.    }

  14.    public Object getTarget() {
  15.        return target;
  16.    }

  17.    public void setTarget(Object target) {
  18.        this.target = target;
  19.    }

  20.    public String getName() {
  21.        return name;
  22.    }

  23.    public void setName(String name) {
  24.        this.name = name;
  25.    }
  26. }

2、观察者的接口如下:

  1. package com.weizhaoyang.observer;

  2. public interface Observer {
  3.    /**
  4.     * 执行动作
  5.     */
  6.    public void  OnAction(MyEvent  myEvent);
  7. }

3、目标的代码改造如下:

  1. package com.weizhaoyang.observer;

  2. import java.util.ArrayList;
  3. import java.util.List;

  4. /**
  5. * 创建目标对象(老师)
  6. */
  7. public class Subject {
  8.     //依赖观察者(学生)
  9.    List<Observer> studentObservers=new ArrayList<Observer>();
  10.    //消息
  11.    List<String>MessageList=new ArrayList<String>();
  12.    //添加观察者
  13.    public void addObserver(Observer observer){
  14.        studentObservers.add(observer);
  15.    }
  16.    //删除观察者
  17.    public void removeObserver(Observer observer){
  18.        studentObservers.remove(observer);
  19.    }
  20.    /**
  21.     * 产生一个行为
  22.     * 逆向
  23.     */
  24.    public void  action(){
  25.        System.out.println("老师开始上课了");
  26.        MessageList.add("action1");
  27.        //通知所有的学生来进行响应

  28.    }
  29.    public void  action1(){
  30.        System.out.println("老师开始上课了");
  31.        MessageList.add("action2");
  32.        //通知所有的学生来进行响应

  33.    }
  34.    public void  action2(){
  35.        System.out.println("老师开始上课了");
  36.        MessageList.add("action3");
  37.        //通知所有的学生来进行响应

  38.    }
  39.    public void  action3(){
  40.        System.out.println("老师开始上课了");
  41.        //MessageList.add("action4");
  42.        //事件
  43.        MyEvent  myEvent=new MyEvent(this,"weizhaoyang");
  44.        //通知所有的学生来进行响应
  45.        if (studentObservers != null && studentObservers.size() > 0){
  46.            for(Observer observer:studentObservers){
  47.                new Thread(){
  48.                    @Override
  49.                    public void run() {
  50.                        observer.OnAction(myEvent);
  51.                    }
  52.                }.start();
  53.            }
  54.        }
  55.    }
  56. }

4、观察者的代码改造如下:

  1. package com.weizhaoyang.observer;

  2. public class StudentObserver implements Observer {
  3.    @Override
  4.    public void OnAction(MyEvent event) {
  5.        System.out.println("收到回调通知"+event.getName());
  6.        System.out.println("学生收到通知,要开始上课了");
  7.    }
  8. }

5、测试类的代码如下:

  1. package com.weizhaoyang.observer;

  2. public class ObserverTest  {
  3.    public static void main(String[] args) {
  4.        Observer observer=new StudentObserver();
  5.        Subject  subject=new Subject();
  6.        subject.addObserver(observer);
  7.        subject.action3();
  8.    }
  9. }

运行的结果如下:

这就是基于事件的观察者模式,在监听器里面就可以依赖目标了。在spring中就是基于事件来设计的。

相关文章
|
30天前
|
Java 调度 开发者
spring的@Scheduled()有几种定时模式?
【10月更文挑战第12天】spring的@Scheduled()有几种定时模式?
71 1
|
1月前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
404 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
|
1月前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
167 2
|
2月前
|
设计模式 Java Spring
spring源码设计模式分析(五)-策略模式
spring源码设计模式分析(五)-策略模式
|
2月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
102 5
|
2月前
|
XML 存储 Java
Spring-源码深入分析(二)
Spring-源码深入分析(二)
|
2月前
|
XML 设计模式 Java
Spring-源码深入分析(一)
Spring-源码深入分析(一)
|
Java 应用服务中间件 数据库连接
Spring全家桶之Spring篇深度分析(一)
Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。
Spring全家桶之Spring篇深度分析(一)
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
162 2