(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<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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容