第一节中的示例过于简单《从零开始理解JAVA事件处理机制(1)》,简单到让大家觉得这样的代码简直毫无用处。但是没办法,我们要继续写这毫无用处的代码,然后引出下一阶段真正有益的代码。

一:事件驱动模型初窥

我们要说事件驱动模型是观察者模式的升级版本,那我们就要说说其中的对应关系:

观察者对应监听器(学生)

被观察者对应事件源(教师)

事件源产生事件,监听器监听事件。爱钻牛角尖的朋友可能会说,我擦,什么叫产生事件,监听事件,事件事件到底什么?

莫慌,如果我们用代码来说事,事件源它就是个类,事件就是事件源中的那几行业务代码。这里面一共牵扯到四个类,事件源(即教师、即被观察者)、事件、监听器接口、具体的监听器(即学生、即观察者)。

就像我们上一篇文章中的第一节提到的一样,JDK中当然有现成的事件模型类,我们不妨来一个一个的查看一下吧。

首先看监听器(即学生、即观察者,大家不要嫌我烦,不停滴括号提醒,这是为了不停滴给大家加深印象),

package java.util;

/**
* A tagging interface that all event listener interfaces must extend.
* @since JDK1.1
*/
public interface EventListener {
}

简单到不能再简单了,对吧,甚至连一个声明的方法都没有,那它存在的意义在哪?还记得面向对象中的上溯造型吗,所以它的意义就在于告诉所有的调用者,我是一个监听器。

再来看看事件源(即教师、即被观察者),

package java.util;

/**
* <p>
* The root class from which all event state objects shall be derived.
* <p>
* All Events are constructed with a reference to the object, the "source",
* that is logically deemed to be the object upon which the Event in question
* initially occurred upon.
*
* @since JDK1.1
*/

public class EventObject implements java.io.Serializable {

private static final long serialVersionUID = 5516075349620653480L;

/**
     * The object on which the Event initially occurred.
     */
    protected transient Object  source;

/**
     * Constructs a prototypical Event.
     *
     * @param    source    The object on which the Event initially occurred.
     * @exception  IllegalArgumentException  if source is null.
     */
    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");

this.source = source;
    }

/**
     * The object on which the Event initially occurred.
     *
     * @return   The object on which the Event initially occurred.
     */
    public Object getSource() {
        return source;
    }

/**
     * Returns a String representation of this EventObject.
     *
     * @return  A a String representation of this EventObject.
     */
    public String toString() {
        return getClass().getName() + "[source=" + source + "]";
    }
}

这个类也很简单,如果说观察者模式中的上层类和结果还带了不少逻辑不少方法的话,那么事件驱动模型中的上层类和接口简直看不到任何东西。没错,

事件驱动模型中,JDK的设计者们进行了最高级的抽象,就是让上层类只是代表了:我是一个事件源,或,我是一个监听者!

二:老师布置作业的事件驱动模型版本

老规矩,让我们先给出类图:

然后,代码实现之:

观察者接口(学生)。由于在事件驱动模型中,只有一个没有任何方法的接口,EventListener,所以,我们可以先实现一个自己的接口。为了跟上一篇的代码保持一致,在该接口中我们声明的方法的名字也叫update。注意,我们当然也可以不取这个名字,甚至还可以增加其它的方法声明,全看我们的业务需要。

package com.zuikc.events;

import java.util.Observable;

public interface HomeworkListener extends java.util.EventListener {

public void update(HomeworkEventObject o, Object arg);
}

继而实现观察者类(学生),如下:

package com.zuikc.events;

public class Student implements HomeworkListener{
    private String name;
    public Student(String name){
        this.name = name;
    }
    @Override
    public void update(HomeworkEventObject o, Object arg) {
        Teacher teacher = o.getTeacher();
        System.out.printf("学生%s观察到(实际是被通知)%s布置了作业《%s》 \n", this.name, teacher.getName(), arg);
    }

}

对比一下上篇,有变动没?

继而实现事件源这个类,如下:

package com.zuikc.events;

public class HomeworkEventObject extends java.util.EventObject {

public HomeworkEventObject(Object source) {
        super(source);
    }
    public HomeworkEventObject(Teacher teacher) {
        super(teacher);
    }
    public Teacher getTeacher(){
        return (Teacher) super.getSource();
    }

}

在这个类中,指的关注的就是这个getTeacher方法,它封装了父类EventObject的getSource方法。理论上,我们使用父类的getSource方法也可行,但是重新在子类封装一下,可读性更强一点。

然后呢,然后就是我们的教师类,如下:

package com.zuikc.events;

import java.util.*;

public class Teacher {
    private String name;
    private List<String> homeworks;
    /*
     * 教师类要维护一个自己监听器(学生)的列表,为什么?
     * 在观察者模式中,教师是被观察者,继承自java.util.Observable,Observable中含了这个列表
     * 现在我们没有这个列表了,所以要自己创建一个
     */
    private Set<HomeworkListener> homeworkListenerList;

public String getName() {
        return this.name;
    }

public Teacher(String name) {
        this.name = name;
        this.homeworks = new ArrayList<String>();
        this.homeworkListenerList  = new HashSet<HomeworkListener>();
    }

public void setHomework(String homework) {
        System.out.printf("%s布置了作业%s \n", this.name, homework);
        homeworks.add(homework);
        HomeworkEventObject event = new HomeworkEventObject(this);
        /*
         * 在观察者模式中,我们直接调用Observable的notifyObservers来通知被观察者
         * 现在我们只能自己通知了~~
         */
        for (HomeworkListener listener : homeworkListenerList) {
            listener.update(event, homework);
        }

}
    public void addObserver(HomeworkListener homeworkListener){
        homeworkListenerList.add(homeworkListener);
    }

}

这个类稍微长了那么一点点,有几个地方值得注意:

第一处地方,Teacher没有父类了,Teacher作为事件源中的Source被封装到HomeworkEventObject中了。这没有什么不好的,业务对象和框架代码隔离开来,解耦的非常好,但是正因为如此,我们需要在Teacher中自己维护一个Student的列表,于是,我们看到了homeworkListenerList这个变量。

第二处,在观察者模式中,我们直接调用Observable的notifyObservers来通知被观察者,现在我们只能靠自己了,于是我们看到了这段代码,

for (HomeworkListener listener : homeworkListenerList) {
    listener.update(event, homework);
}

这一点问题也没有,我们继续来看客户端代码吧:

package com.zuikc.events;

import java.util.EventListener;

public class Client {

public static void main(String[] args) {
        Student student1= new Student("张三");
        Student student2 = new Student("李四");
        Teacher teacher1 = new Teacher("zuikc");
        teacher1.addObserver(student1);
        teacher1.addObserver(student2);
        teacher1.setHomework("事件机制第二天作业");
    }

}

结果如下:

从客户端的角度来说,我们几乎完全没有更改任何地方,跟观察者模式的客户端代码一模一样,但是内部的实现机制上,我们却使用了事件机制。

现在我们来总结下,观察者模式和事件驱动模型的几个不同点:

1:事件源不再继承任何模式或者模型本身的父类,彻底将业务代码解耦出来;

2:在事件模型中,每个监听者(观察者)都需要实现一个自己的接口。没错,看看我们的鼠标事件,分表就有单击、双击、移动等等的事件,这分别就是增加了代码的灵活性;

不管怎么说,我们用一堆小白代码实现了一个事件驱动模型的样例,虽然没什么实际用处,但也解释了原理,接下来的一节,我们就要看看那些稍微复杂且看上去很有用的代码了!

从零开始理解JAVA事件处理机制(2)的更多相关文章

  1. 从零开始理解JAVA事件处理机制(3)

    我们连续写了两小节的教师-学生的例子,必然觉得无聊死了,这样的例子我们就是玩上100遍,还是不知道该怎么写真实的代码.那从本节开始,我们开始往真实代码上面去靠拢. 事件最容易理解的例子是鼠标事件:我们 ...

  2. 从零开始理解JAVA事件处理机制(1)

    “事件”这个词已经被滥用了.正因为“事件”的被滥用,很多人在用到事件的时候不求甚解,依样画葫芦,导致学习工作了很多年,还是不清楚什么是事件处理器.什么是事件持有者.所以,如果你对于Event这个词还是 ...

  3. Java事件处理机制(深入理解)

    本文是关于Java事件处理机制的梳理,以及有重点的介绍一些注意点,至于基础的概念啥的不多赘述. 一.Java事件处理机制初步介绍(看图理解) 根据下图,结合生活实际,可以得知监护人可以有多个,坏人对小 ...

  4. java事件处理机制

    java中的事件机制的参与者有3种角色:   1.event object:就是事件产生时具体的"事件",用于listener的相应的方法之中,作为参数,一般存在与listerne ...

  5. 理解Java类加载机制(译文)

    理解java类加载机制 你想写类加载器?或者你遇到了ClassCastException异常,或者你遇到了奇怪的LinkageError状态约束异常.应该仔细看看java类的加载处理了. 什么是类加载 ...

  6. Java基础 -- 深入理解Java异常机制

    异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API中Throwable类的众多子类描述各种不同的异常. ...

  7. [转]Java事件处理机制- 事件监听器的四种实现方式

    原文来自http://stefan321.iteye.com/blog/345221 自身类作为事件监听器 外部类作为事件监听器 匿名内部类作为事件监听器 内部类作为事件监听器 自身类作为事件监听器: ...

  8. 【转】深入理解java异常处理机制

    深入理解java异常处理机制 ; int c; for (int i = 2; i >= -2; i--) { c = b / i; System.out.println("i=&qu ...

  9. 转:一个经典例子让你彻彻底底理解java回调机制

    一个经典例子让你彻彻底底理解java回调机制 转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17483273 ...

随机推荐

  1. LED操作

    灯上拉 GPIO_InitTypeDef GPIO_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); GPIO_InitS ...

  2. JQuery插件之Animate.css和 jquery-aniview

    Animate.css 一款强大的预设css3动画库 简介 animate.css 是一个来自国外的 CSS3 动画库,它预设了抖动(shake).闪烁(flash).弹跳(bounce).翻转(fl ...

  3. yii框架后台过滤器的使用 安全防护

    Yii过滤器简介 过滤器是一段代码,可被配置在控制器动作执行之前或之后执行.例如, 访问控制过滤器将被执行以确保在执行请求的动作之前用户已通过身份验证:性能过滤器可用于测量控制器执行所用的时间. 一个 ...

  4. crash部分命令用法

    Set set [pid | taskp | [-c cpu] | -p] | [crash_variable [setting]] | -v 1.设置要显示的内容,内容一般以进程为单位. Set p ...

  5. Dora.Interception: 一个为.NET Core度身定制的AOP框架

    多年从事框架设计开发使我有了一种强迫症,那就是见不得一个应用里频繁地出现重复的代码.之前经常Review别人的代码,一看到这样的程序,我就会想如何将这些重复的代码写在一个地方,然后采用“注入”的方式将 ...

  6. openresty源码剖析——lua代码的执行

    上一篇文章中我们讨论了openresty是如何加载lua代码的 那么加载完成之后的lua代码又是如何执行的呢 ##代码的执行  在init_by_lua等阶段  openresty是在主协程中通过lu ...

  7. Day2 Python的运算符及三大语句控制结构

    Python的运算符 Python语言支持以下类型的运算符: 算术运算符 比较(关系)运算符 赋值运算符 逻辑运算符 位运算符 成员运算符 身份运算符 运算符优先级 Python的三大语句控制结构: ...

  8. 工具类总结---(四)---Sharedpreferences保存

    用于保存具有对应关系的键值对 import android.content.Context; import android.content.SharedPreferences; import java ...

  9. 在iOS应用程序中使用Frida绕过越狱检测

           阿里聚安全在之前的三篇博客中介绍了利用Frida攻击Android应用程序,整个过程仿佛让开发者开启上帝视角,在本篇博客中,我们将会介绍在iOS应用程序中使用Frida绕过越狱检测.即使 ...

  10. iOS 发布证书提示 此证书的签发者无效 解决办法

    1. 打开钥匙串  查看发布证书 都是提示 此证书的签发者无效   解决办法 : 2. 到了 第 4 步骤 再去 查看 发布证书 就会 显示  此证书有效 3.  如果还不可以 就 把 Apple W ...