定义
定义对象的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式是行为型模式之一。包含观察者模式包括观察者与被观察者两个基本元素,观察者会注册到被观察者中,而被观察者会保持和观察者的对应关系。
如果被观察的对象产生一些观察者感兴趣的变更,则观察者会得到通知从而去执行相关的操作。
常见的观察者模式
提到观察者模式,首先会想到前端中常用的事件机制。例如为dom元素绑定事件:
$(document).click(function (e) {
console.dir(e);
});
这里的匿名function就是观察者,而document则是被观察者,.click(function)则是观察者注册的过程,此后document发生click事件时,被观察者则会收到通知,从而执行自己的逻辑console.dir(e)。
使用观察者模式
现在我们使用Java来模拟观察者模式。
先创建事件,包含事件源,通知目标,回调方法以及触发者等属性。
/**
* 事件
*/
public class Event {
private Object source; // 事件源
private Object target; // 通知目标
private Method callback; // 回调方法名称
private String trigger; // 触发者
private long time;
public Event(Object target, Method callback) {
this.target = target;
this.callback = callback;
}
// 省略getter、setter
}
定义事件类型,此处定义添加、删除两种类型。
/**
* 事件类型
*/
public enum EventType {
/**
* 添加
*/
ADD,
/**
* 删除
*/
RMOVE
}
定义抽象被观察者(主题),包含主题名称,保持与观察者引用映射的容器,以及事件触发的方法。
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* 抽象主题
* 定义主题通用的容器、事件注册及事件触发
*/
public class AbstractSubject {
protected String name;
protected Map<Enum,Event> eventMap = new HashMap<>(); // 注册容器
public AbstractSubject() {}
protected AbstractSubject(String name) {
this.name = name;
}
/**
* 事件注册
* @param eventType
* @param target
* @param callback
*/
public void addLisenter(Enum eventType, Object target, Method callback) {
eventMap.put(eventType, new Event(target, callback));
}
/**
* 事件触发
* @param eventType
*/
protected void trigger(Enum eventType) {
Event event = this.eventMap.get(eventType);
if(null == event) {
return;
}
event.setSource(this);
event.setTrigger(eventType.toString());
event.setTime(System.currentTimeMillis());
try {
event.getCallback().invoke(event.getTarget(), event);
} catch (Exception e1) {
e1.printStackTrace();
}
}
// 省略getter、setter
}
定义具体主题:
/**
* 主题,被观察者
*/
public class Subject extends AbstractSubject {
public Subject(String name) {
super.name = name;
}
public void add() {
trigger(EventType.ADD);
}
public void remove() {
trigger(EventType.RMOVE);
}
}
定义观察者,包含添加、删除事件对应的回调方法。
/**
* 观察者
*/
public class Observer {
public void onAdd(Event event) {
System.out.println("收到" + event.getTrigger() + "的添加事件");
}
public void onRemove(Event event) {
System.out.println("收到" + event.getTrigger() + "的删除事件");
}
}
测试类:
/**
* 测试类
*/
public class Test {
public static void main(String[] args) throws NoSuchMethodException {
// 观察者
Observer observer = new Observer();
// 观察者收到通知后执行的方法
Method onAdd = Observer.class.getMethod("onAdd", Event.class);
Method onRemove = Observer.class.getMethod("onRemove", Event.class);
// 被观察者
Subject subject = new Subject("目标1号");
// 事件绑定
subject.addLisenter(EventType.ADD, observer, onAdd);
subject.addLisenter(EventType.RMOVE, observer, onRemove);
// 被观察者触发事件
subject.add();
subject.remove();
}
}
其中,得到观察者和主题对象后,进行观察者的注册,然后主题执行动作触发事件,这是整个流程。
如果需要做成主题和观察者一对多的映射,则将Event的target改成集合类型,如下:
private List<Object> targets; // 通知目标