(11)spring常用模式--------观察者模式

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 eventMap = new HashMap();

    //添加监听者对象
    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

你可能感兴趣的:((11)spring常用模式--------观察者模式)