观察者模式
在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(){
@Override
public void run() {
observer.OnAction();
}
}.start();
}
}
}
}
提供一个观察者:
package com.weizhaoyang.observer;
public class StudentObserver implements Observer {
@Override
public 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(){
@Override
public 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(){
@Override
public 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(){
@Override
public 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(){
@Override
public 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(){
@Override
public void run() {
observer.OnAction(myEvent);
}
}.start();
}
}
}
}
4、观察者的代码改造如下:
package com.weizhaoyang.observer;
public class StudentObserver implements Observer {
@Override
public 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中就是基于事件来设计的。