1.观察者模式简介
观察者模式:定义对象间的一种一对多的依赖关系
, 当一个对象的状态发生改变时
, 所有依赖于它的对象都得到通知并被自动更新
应用场景: 监听器
、 日志收集
、 短信通知
、邮件通知
在spring中的应用: Spring 中 Observer 模式常用的地方是 Listener 的实现。 如 ApplicationListener
优点:观察者和被观察者是抽象耦合的
,建立一套触发机制
下面通过一张uml图来了解的观察者的结构模型,从下图发现,主题对象包含了观察者,具体的观察者对象存在着主题对象的引用(当主题对象的属性状态发生改变时可以获取主题对象的信息)
观察者模式.png
2.观察者的模式实例演示
在实例演示之前,先了解一下java事件模型
目标角色(如界面组件)负责发布事件,而观察者角色(事件处理者)可以向目标订阅它所感兴趣的事件。当一个具体目标产生一个事件时,它将通知所有订阅者。
事件的发布者称为事件源(Event Source)
,而订阅者称为事件监听器(Event Listener)
,在这个过程中还可以通过事件对象(Event Object)来传递与事件相关的信息
,可以在事件监听者的实现类中实现事件处理,因此事件监听对象又可以称为事件处理对象
。事件源对象
、事件监听对象
(事件处理对象)和事件对象
构成了Java事件处理模型
的三要素
下面演示的是鼠标的操作触发鼠标对应的绑定的事件的例子
事件对象
**
* @Project: spring
* @description: 事件对象 一个中间对象,保存了事件源,事件的通知对象和方法,以及触发类型,触发时间
* 这里面用到链式的写法
* @author: sunkang
* @create: 2018-09-06 10:47
* @ModificationHistory who when What
**/
public class Event {
//事件源,谁触发的
private Object source;
//触发类型的标记
private String trigger;
//通知的目标对象
private Object target;
//通知的目标的方法
private Method callback;
//触发时间
private long time;
public Event(Object target, Method method) {
this.target = target;
this.callback = method;
}
public Object getSource() {
return source;
}
public Event setSource(Object source) {
this.source = source;
return this;
}
public String getTrigger() {
return trigger;
}
public Event setTrigger(String trigger) {
this.trigger = trigger;
return this;
}
public Object getTarget() {
return target;
}
public Event setTarget(Object target) {
this.target = target;
return this;
}
public Method getCallback() {
return callback;
}
public void setCallback(Method callback) {
this.callback = callback;
}
public long getTime() {
return time;
}
public Event setTime(long time) {
this.time = time;
return this;
}
@Override
public String toString() {
return "Event{" +
"source=" + source +
", trigger='" + trigger + '\'' +
", target=" + target +
", callback=" + callback +
", time=" + time +
'}';
}
}
抽象的时间源对象,提供公用的事件注册,事件移除,事件触发
/**
* @Project: spring
* @description: 可以认为是一个抽象主题对象, 可以添加和移除观察者,当需要触发的时候,就调用触发方法
* @author: sunkang
* @create: 2018-09-06 10:55
* @ModificationHistory who when What
**/
public abstract class EventListener {
//保存事件的容器
private Map<Enum,Event> eventMap = new HashMap<Enum, Event>();
//添加监听者对象
public void addListener(Enum e , Object target , Method method){
Event event =new Event(target,method);
eventMap.put(e,event);
}
//移除监听者对象
public void removeListener(Enum e){
eventMap.remove(e);
}
/**
* 通过事件来触发
* @param event
*/
public void trigger(Event event){
//设置源事件
event.setSource(this);
event.setTime(System.currentTimeMillis());
try {
event.getCallback().invoke(event.getTarget(),event);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
//通过触发类型来触发对应的观察者
public void trigger(Enum e){
if(!eventMap.keySet().contains(e)){
return;
}
//先从容器中获取事件,并设置触发类型
trigger( eventMap.get(e).setTrigger(e.toString()));
}
}
鼠标事件对象,具体的主题对象,继承了EventListener
/**
* @Project: spring
* @description: 具体的主题对象,认为是事件对象 鼠标对象,当单击鼠标,就触发单击的时间
* @author: sunkang
* @create: 2018-09-06 11:09
* @ModificationHistory who when What
**/
public class Mouse extends EventListener {
public void click(){
System.out.println("鼠标单击");
this.trigger(MouseEventType.ON_CLICK);
}
public void doubleClick(){
System.out.println("鼠标双击");
this.trigger(MouseEventType.ON_DOUBLE_CLICK);
}
public void up(){
System.out.println("鼠标弹起");
this.trigger(MouseEventType.ON_UP);
}
public void down(){
System.out.println("鼠标按下");
this.trigger(MouseEventType.ON_DOWN);
}
}
事件监听对象 ,可以认为是观察者
/**
* @Project: spring
* @description: 可以认为是观察者,认为是事件监听对象 这里是通过反射调用来通知观察者的
* @author: sunkang
* @create: 2018-09-06 11:13
* @ModificationHistory who when What
**/
public class MouseEventCallback {
public void onClick(Event e){
System.out.println("=======触发鼠标单击事件========\n" + e);
}
public void onDoubleClick(Event e){
System.out.println("=======触发鼠标双击事件========\n" + e);
}
public void onUp(Event e){
System.out.println("=======触发鼠标弹起事件========\n" + e);
}
public void onDown(Event e){
System.out.println("=======触发鼠标按下事件========\n" + e);
}
public void onMove(Event e){
System.out.println("=======触发鼠标移动事件========\n" + e);
}
}
事件的类型
/**
* @Project: spring
* @description: 事件的类型
* @author: sunkang
* @create: 2018-09-06 11:10
* @ModificationHistory who when What
**/
public enum MouseEventType {
ON_CLICK,
ON_DOUBLE_CLICK,
ON_UP,
ON_DOWN
}
观察者模拟测试
/**
* @Project: spring
* @description: 观察者测试 鼠标对象测试
*观察者和被观察者之间没有必然联系
*注册的时候,才产生联系
*解耦
* @author: sunkang
* @create: 2018-09-06 11:14
* @ModificationHistory who when What
**/
public class MouseTest {
public static void main(String[] args) throws NoSuchMethodException {
//事件监听对象
MouseEventCallback target = new MouseEventCallback();
//事件监听对象 对应绑定的方法
Method onClickCallback =target.getClass().getDeclaredMethod("onClick", Event.class);
Mouse mouse = new Mouse();
//添加观察者对象,这里这是把通知的目标和方法进行封装到一个中间的事件对象身上
mouse.addListener(MouseEventType.ON_CLICK,target,onClickCallback);
//通知观察者对象,在这里是触发事件,利用了反射调用来进行通知
mouse.trigger(MouseEventType.ON_CLICK);
}
}
测试结果
装饰者模式的测试结果.png