第一节中的示例过于简单《从零开始理解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. Broker节点

    在druid集群环境中 broker节点的作用是查询.它知道metadata 通过zookeeper发送到了集群中的哪个节点,从而能够准确的查询到.broker也把各个节点的结果汇聚到一个节点中.On ...

  2. css系列:input的placeholder在safari下设置行高失效

    在项目中遇到input的placeholder在safari下设置行高失效的问题,问度娘后未得治原因,倒是有解决办法: 方法一:使用padding使提示文字居中,如果font-size:14px,UI ...

  3. a标签去掉默认样式并自定义样式

    a { text-decoration: none;//去掉下划线 color: inherit; -webkit-user-select: none; -moz-user-select: none; ...

  4. 分布式锁与实现(一)——基于Redis实现

    概述 目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们"任何一个分布式系统都无法同时满足一致性(Consisten ...

  5. .NET跨平台实践:再谈用C#开发Linux守护进程

    Linux守护进程是Linux的后台服务进程,相当于Windows服务进程,对于为Linux开发服务程序的朋友来说,Linux守护进程相关技术是必不可少的,因为这个技术不仅仅是开发守护进程,还可以拓展 ...

  6. dotnetcore中的IOptionsSnapshot<>的自动更新原理

    1.首先讲讲ChangeToken.OnChange方法: 原理是给一个CancellationToken注册一个消费者委托,调用CancellationToken的Cancel的时候会调用这个Can ...

  7. 设计模式的征途—3.抽象工厂(Abstract Factory)模式

    上一篇的工厂方法模式引入了工厂等级结构,解决了在原来简单工厂模式中工厂类职责太重的原则,但是由于工厂方法模式的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,从而增加系统开销.那么,我们应该 ...

  8. macOS 下配置 MAMP 开发环境(Mac + Apache + Mysql + PHP)

    macOS 中已经内置了 PHP.Python.Ruby.Perl 等常用的脚本语言,以及 Apache HTTP 服务器,所以使用起来非常方便.本文以最新的 macOS Sierra 10.12 配 ...

  9. css浮动布局,浮动原理,清除(闭合)浮动方法

    css浮动 1.什么是浮动:在我们布局的时用到的一种技术,能够方便我们进行布局,通过让元素浮动,我们可以使元素在水平上左右移动,再通过margin属性调整位置 2.浮动的原理:使当前元素脱离普通流,相 ...

  10. [Cake] 0.C# Make自动化构建-简介

    0.Cake是什么? Cake是C# Make的缩写,是一个基于C# DSL的自动化构建系统.它可以用来编译代码,复制文件以及文件夹,运行单元测试,压缩文件以及构建Nuget包等等. 熟悉大名鼎鼎的M ...