观察者模式
在Spring里面用的就是事件监听,用事件监听的方式来扩展了观察者模式,理解了观察者模式就理解了顺序编程和逆向编程。
在我们解决某个问题的时候:请求方法1,会依赖请求方法2的结果,同时请求方法2,会依赖请求方法3的结果,这叫做顺序依赖。写程序的时候也是从上往下调,一直返回结果。依赖:就是自己解决不了这个问题,需要依赖另一个方法来帮解决这个问题
也可以逆序依赖,方法3依赖方法2的响应结果,方法2依赖方法1的响应结果,依赖产生行为后的一个状态[消息,事件],简称回调,类似js,jq中的事件监听器的模式。
实现方式:1、事件:观察者模式:这里有目标,和观察者,观察者观察目标,再进行响应。比如:老师讲课,学生听课就是典型的观察者模式。代码如下:
提供一个接口:
package com.weizhaoyang.observer;public interface Observer {/*** 执行动作*/public void OnAction();}
提供一个目标类:
package com.weizhaoyang.observer;import java.util.ArrayList;import java.util.List;/*** 创建目标对象(老师)*/public class Subject {//依赖观察者(学生)List<Observer> studentObservers=new ArrayList<Observer>();//添加观察者public void addObserver(Observer observer){studentObservers.add(observer);}//删除观察者public void removeObserver(Observer observer){studentObservers.remove(observer);}/*** 产生一个行为* 逆向*/public void action(){System.out.println("老师开始上课了");//通知所有的学生来进行响应,这种模式称之为推if (studentObservers != null && studentObservers.size() > 0){for(Observer observer:studentObservers){new Thread(){@Overridepublic void run() {observer.OnAction();}}.start();}}}}
提供一个观察者:
package com.weizhaoyang.observer;public class StudentObserver implements Observer {@Overridepublic void OnAction() {System.out.println("学生收到通知,要开始上课了");}}
测试的类如下:
package com.weizhaoyang.observer;public class ObserverTest {public static void main(String[] args) {Observer observer=new StudentObserver();Subject subject=new Subject();subject.addObserver(observer);subject.action();}}
运行的结果如下:上面的异步通知可以称之为事件。类似消息队列。
每一个产生行为之后的就称之为消息。如果不想要去立刻发出消息的话,可以把这四个行为放到缓存里面。
package com.weizhaoyang.observer;import java.util.ArrayList;import java.util.List;/*** 创建目标对象(老师)*/public class Subject {//依赖观察者(学生)List<Observer> studentObservers=new ArrayList<Observer>();//消息List<String>MessageList=new ArrayList<String>();//添加观察者public void addObserver(Observer observer){studentObservers.add(observer);}//删除观察者public void removeObserver(Observer observer){studentObservers.remove(observer);}/*** 产生一个行为* 逆向*/public void action(){System.out.println("老师开始上课了");MessageList.add("action1");//通知所有的学生来进行响应if (studentObservers != null && studentObservers.size() > 0){for(Observer observer:studentObservers){new Thread(){@Overridepublic void run() {observer.OnAction();}}.start();}}}public void action1(){System.out.println("老师开始上课了");MessageList.add("action2");//通知所有的学生来进行响应if (studentObservers != null && studentObservers.size() > 0){for(Observer observer:studentObservers){new Thread(){@Overridepublic void run() {observer.OnAction();}}.start();}}}public void action2(){System.out.println("老师开始上课了");MessageList.add("action3");//通知所有的学生来进行响应if (studentObservers != null && studentObservers.size() > 0){for(Observer observer:studentObservers){new Thread(){@Overridepublic void run() {observer.OnAction();}}.start();}}}public void action3(){System.out.println("老师开始上课了");//消息MessageList.add("action4");//通知所有的学生来进行响应if (studentObservers != null && studentObservers.size() > 0){for(Observer observer:studentObservers){new Thread(){@Overridepublic void run() {observer.OnAction();}}.start();}}}}
上面的代码我们可以用通知统一的通知上面的四个消息。这时不依赖动作的行为,而是依赖消息队列 MessageList。而kafka,rabbitmq这些消息队列只是封装 了暴漏出接口给我们用而已。可以把上面的代码再次的改造,把消息放入到缓存里面,不是立马产生消息,开启一个定时轮询器,用动态线程轮询的方式去消息,而这种模式称之为拉模型。如果线程很好资源的话,可以用线程池。
package com.weizhaoyang.observer;import java.util.ArrayList;import java.util.List;/*** 创建目标对象(老师)*/public class Subject {//依赖观察者(学生)List<Observer> studentObservers=new ArrayList<Observer>();//消息List<String>MessageList=new ArrayList<String>();//添加观察者public void addObserver(Observer observer){studentObservers.add(observer);}//删除观察者public void removeObserver(Observer observer){studentObservers.remove(observer);}/*** 产生一个行为* 逆向*/public void action(){System.out.println("老师开始上课了");MessageList.add("action1");//通知所有的学生来进行响应}public void action1(){System.out.println("老师开始上课了");MessageList.add("action2");//通知所有的学生来进行响应}public void action2(){System.out.println("老师开始上课了");MessageList.add("action3");//通知所有的学生来进行响应}public void action3(){System.out.println("老师开始上课了");MessageList.add("action4");//通知所有的学生来进行响应}}
推消息是主动的推消息,拉是主动的从消息队列里面去拉取消息。这就是从观察者设计模式延申到消息队列一些知识点。下面的是最简单的消息队列:每产生一个动作,就发送一条消息。
如果不直接消费的话,就可以从messgeList里面去拉取感兴趣的消息,在spring中用的是事件的方式,代码改造如下:
1、首先加一个事件:
package com.weizhaoyang.observer;/*** 事件对象*/public class MyEvent {//目标对象public Object target;//其他参数private String name;public MyEvent(Object target, String name) {this.target = target;this.name = name;}public Object getTarget() {return target;}public void setTarget(Object target) {this.target = target;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
2、观察者的接口如下:
package com.weizhaoyang.observer;public interface Observer {/*** 执行动作*/public void OnAction(MyEvent myEvent);}
3、目标的代码改造如下:
package com.weizhaoyang.observer;import java.util.ArrayList;import java.util.List;/*** 创建目标对象(老师)*/public class Subject {//依赖观察者(学生)List<Observer> studentObservers=new ArrayList<Observer>();//消息List<String>MessageList=new ArrayList<String>();//添加观察者public void addObserver(Observer observer){studentObservers.add(observer);}//删除观察者public void removeObserver(Observer observer){studentObservers.remove(observer);}/*** 产生一个行为* 逆向*/public void action(){System.out.println("老师开始上课了");MessageList.add("action1");//通知所有的学生来进行响应}public void action1(){System.out.println("老师开始上课了");MessageList.add("action2");//通知所有的学生来进行响应}public void action2(){System.out.println("老师开始上课了");MessageList.add("action3");//通知所有的学生来进行响应}public void action3(){System.out.println("老师开始上课了");//MessageList.add("action4");//事件MyEvent myEvent=new MyEvent(this,"weizhaoyang");//通知所有的学生来进行响应if (studentObservers != null && studentObservers.size() > 0){for(Observer observer:studentObservers){new Thread(){@Overridepublic void run() {observer.OnAction(myEvent);}}.start();}}}}
4、观察者的代码改造如下:
package com.weizhaoyang.observer;public class StudentObserver implements Observer {@Overridepublic void OnAction(MyEvent event) {System.out.println("收到回调通知"+event.getName());System.out.println("学生收到通知,要开始上课了");}}
5、测试类的代码如下:
package com.weizhaoyang.observer;public class ObserverTest {public static void main(String[] args) {Observer observer=new StudentObserver();Subject subject=new Subject();subject.addObserver(observer);subject.action3();}}
运行的结果如下:
这就是基于事件的观察者模式,在监听器里面就可以依赖目标了。在spring中就是基于事件来设计的。