观察者模式定义了对象之间的一对多依赖,让多个观察者对象同时监听一个主体,当主体对象发生变化时,它的所有观察者都会收到通知。观察者模式也叫发布订阅模式,主要用于在关联行为之间建立一套触发机制的场景。
下面通过我们平时最常用的键盘鼠标相关的监听事件作为例子,来熟悉观察者模式。
一、首先创建Event类
public class Event {
// 事件源,事件是由谁发起的,保存起来
private Object source;
// 事件触发,要通知谁
private Object target;
// 事件名称,触发的什么事件
private String trigger;
// 回调函数,事件触发,要做什么动作
private Method callback;
// 事件触发的时间
private long time;
public Event( Object target,Method callback) {
this.target = target;
this.callback=callback;
}
public Event(Object source) {
this.source = source;
}
public Object getSource() {
return source;
}
public Object getTarget() {
return target;
}
public Method getCallback() {
return callback;
}
public String getTrigger() {
return trigger;
}
public long getTime() {
return time;
}
public Event setSource(Object source) {
this.source = source;
return this;
}
public Event setTarget(Object target) {
this.target = target;
return this;
}
public Event setTrigger(String trigger) {
this.trigger = trigger;
return this;
}
public Event setTime(long time) {
this.time = time;
return this;
}
@Override
public String toString() {
return "Event{" +
"source=" + source +
", target=" + target +
", trigger='" + trigger + '\'' +
", callback=" + callback +
", time=" + time +
'}';
}
}
二、创建事件监听EventLisenter 类
public class EventLisenter {
protected Map<String, Event> events = new HashMap<String, Event>();
public void addLisenter(String eventType, Object target) {
try {
this.addLisenter(eventType,
target,
target.getClass().getMethod("on" + toUpperFirstCase(eventType),
Event.class));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 注册事件
*
* @param eventType
* @param target
* @param callback
*/
public void addLisenter(String eventType, Object target, Method callback) {
events.put(eventType, new Event(target, callback));
}
// 触发,只要有动作就会触发
private void trigger(Event event) {
event.setSource(this);
event.setTime(System.currentTimeMillis());
try {
if (event.getCallback() != null) {
event.getCallback().invoke(event.getTarget(), event);
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 事件名称触发
protected void trigger(String trigger) {
if (!this.events.containsKey(trigger)) {
return;
}
trigger(this.events.get(trigger).setTrigger(trigger));
}
/**
* 首字母大写
*
* @param str
* @return
*/
private String toUpperFirstCase(String str) {
char[] chars = str.toCharArray();
chars[0] -= 32;
return String.valueOf(chars);
}
}
三、创建鼠标事件类型接口 MouseEventType,定义一些行为
public interface MouseEventType {
static String ON_CLICK = "click";
static String ON_DOUBLE_CLICK = "doubleClick";
static String ON_UP = "up";
static String ON_DOWN = "down";
static String ON_MOVE = "move";
static String ON_WHEEL = "wheel";
static String ON_OVER = "over";
static String ON_BLUR = "blur";
static String ON_FOCUS = "focus";
}
四、创建 Mouse 类
public class Mouse extends EventLisenter {
public void click(){
System.out.println("调用单击方法");
this.trigger(MouseEventType.ON_CLICK);
}
public void doublrClick(){
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);
}
public void move(){
System.out.println("调用移动方法");
this.trigger(MouseEventType.ON_MOVE);
}
public void wheel(){
System.out.println("调用滚动方法");
this.trigger(MouseEventType.ON_WHEEL);
}
public void over(){
System.out.println("调用悬停方法");
this.trigger(MouseEventType.ON_OVER);
}
public void blur(){
System.out.println("调用获焦方法");
this.trigger(MouseEventType.ON_BLUR);
}
public void focus(){
System.out.println("调用失焦方法");
this.trigger(MouseEventType.ON_FOCUS);
}
}
五、创建 MouseEventCallback
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);
}
public void onWheel(Event e){
System.out.println("======获取鼠标滚动事件======"+"\n"+e);
}
public void onOver(Event e){
System.out.println("======获取鼠标悬浮事件======"+"\n"+e);
}
public void onBlur(Event e){
System.out.println("======获取鼠标获焦事件======"+"\n"+e);
}
public void onFocus(Event e){
System.out.println("======获取鼠标失焦事件======"+"\n"+e);
}
}
六、测试代码如下
public class Test {
public static void main(String[] args) {
MouseEventCallback callback = new MouseEventCallback();
// 注册行为
Mouse mouse = new Mouse();
mouse.addLisenter(MouseEventType.ON_CLICK,callback);
mouse.addLisenter(MouseEventType.ON_DOUBLE_CLICK,callback);
mouse.addLisenter(MouseEventType.ON_UP,callback);
mouse.addLisenter(MouseEventType.ON_DOWN,callback);
mouse.addLisenter(MouseEventType.ON_MOVE,callback);
mouse.addLisenter(MouseEventType.ON_OVER,callback);
mouse.addLisenter(MouseEventType.ON_WHEEL,callback);
mouse.addLisenter(MouseEventType.ON_BLUR,callback);
mouse.addLisenter(MouseEventType.ON_FOCUS,callback);
// 鼠标事件
mouse.click();
mouse.focus();
mouse.down();
}
}
打印结果如下:
调用单击方法
======获取鼠标单击事件======
Event{source=com.xiang.observer.Mouse@511d50c0, target=com.xiang.observer.MouseEventCallback@60e53b93, trigger='click', callback=public void com.xiang.observer.MouseEventCallback.onClick(com.xiang.observer.Event), time=1568537813240}
调用失焦方法
======获取鼠标失焦事件======
Event{source=com.xiang.observer.Mouse@511d50c0, target=com.xiang.observer.MouseEventCallback@60e53b93, trigger='focus', callback=public void com.xiang.observer.MouseEventCallback.onFocus(com.xiang.observer.Event), time=1568537813242}
调用按下方法
======获取鼠标按下事件======
Event{source=com.xiang.observer.Mouse@511d50c0, target=com.xiang.observer.MouseEventCallback@60e53b93, trigger='down', callback=public void com.xiang.observer.MouseEventCallback.onDown(com.xiang.observer.Event), time=1568537813242}
Process finished with exit code 0
我们可以看到,首先是把所有的监听对象注册进来,也就是事先确定有哪些观察者。然后调用被观察者的相应的方法,如:mouse.click() mouse.focus() 等。通过这些触发事件会调用事件监听中的trigger方法,通过反射来调用(通知)观察者中对应的函数,来实现发布订阅的功能。