第四讲 Event

今天我们来谈一谈Java里面的Event事件机制

程序的结构在不同的时代是在变化的。刚学编程序的时候,老师总会讲,程序是一个流程,线性执行,分支跳转,循环,有时候加上递归。我们总是能一步步跟踪下来,知道程序确切的运行次序。后来就会碰到事件的概念,程序先是准备好了,然后等待你做出某种反应,输入,键,鼠标,程序获取事件的消息,执行相关的动作。

这种程序结构之下,不再有事先确定的运行次序了。

刚开头遇到这种程序的时候,还真有点不习惯。印象最深刻的就是将近三十年前刚学到Windows编程的时候,看的第一个程序简直把人弄懵了。

我把程序片段贴下来,你们当欣赏历史文物看看:

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){
    RegisterClass (&wndclass)
    hwnd = CreateWindow( szAppName,	// window class name
    ShowWindow (hwnd, iCmdShow) ;
    UpdateWindow (hwnd) ;
    while (GetMessage (&msg, NULL, 0, 0)) {
	    TranslateMessage (&msg) ;
	    DispatchMessage (&msg) ;
    }
    return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
    switch (message) {
	case 	WM_PAINT:
	    hdc = BeginPaint (hwnd, &ps) ;
	    GetClientRect (hwnd, &rect) ;
	   DrawText (hdc, TEXT ("Hello, World!"), -1, &rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
	    EndPaint (hwnd, &ps) ;
	    return 0 ;
    }
    return DefWindowProc (hwnd, message, wParam, lParam) ;
}

你看上面的C程序代码,刚开头就是创建了一个窗口,然后一个死循环等待消息while (GetMessage (&msg, NULL, 0, 0)),消息来了就分派出去,交给相应的程序来处理。

这个处理的代码就是WndProc(),里面根据不同的消息类型执行不同的动作(第一次瞪大了眼睛打着灯笼才终于看到了“Hello World!”)。

Windows上写一个Hello World就这么麻烦!
但是它生命力顽强,最后成长为主流的模式。

我想这种基于事件驱动的方式是一个主要的优势。程序像一个服务机构,客户有什么需求,发来消息,服务机构去处理。这种程序结构很贴近人的行为

我们可以进一步联想到面向对象编程的范式,它认为一个系统是由一个个对象构成的,每个对象有自己的功能和数据,独立成单元,发生什么事件后,通过事件消息传递给别的对象进行通知处理。

这个范式最后成为主流,现在几乎所有的系统都是按照这个范式构建的。

这种方式为什么好呢?理论上的研究表明,需求构成了“问题空间”,程序构成了“解决空间”,两个空间的相似度决定了解决的困难度

传统上,我们要解决一个问题,程序给我们提供的却是寄存器、内存、加法这一类机器的概念术语,所以那个时候将问题空间映射到解决空间的时候很复杂。而面向对象事件驱动的模型,跟现实世界的问题空间有一定程度的相似度,我们能够比较省力地进行映射,解决问题。这个现实世界,本就是一个一个主体客体构成,它们发生了什么事情,本来就是通过消息传递方式联系在一起的。

聊了这些理论上的东西,我们回过头来看Java是怎么弄的。

在Java的事件概念中,有三个东西要了解,一个是事件源,一个是事件消息,一个是事件监听者。这三个词字如其意,不解释。流程是事件源发生了某事件的时候,发出事件消息,由事件监听者接受处理。事件从事件源到监听者的传送是通过对监听者的方法调用进行的(这一点有点意外,刚开头还以为是某种“消息传递”机制

这个机制是存在的,在探讨更大规模的软件结构的时候,会介绍到。我们现在讨论的是一种代码结构,还不是软件结构,更加不是系统结构。我这里用代码结构、软件结构、系统结构三个词表达不同层次的程序规模。)

我们先来看如何定义事件。在java.util中提供了EventObject,所有的事件都要继承它。

我们自己来定义一个,代码如下(MyEvent.java):

package com.test;
import java.util.EventObject;
public class MyEvent extends EventObject {
     private int state;
     private String msg;
 
     public MyEvent(Object source) {
         super(source);
         state = ((Source)source).getState();
         msg = ((Source)source).getMessage();
     }
     public int getSourceState() {
         return this.state;
     }
     public String getSourceMessage() {
         return this.msg;
     }
}

上面定义了一个由Source触发出来的事件MyEvent。构造函数可以有多个,我这里只用了一个默认的,传递的值是source。event中简单记录了状态和一条消息。

我们再看怎么定义事件监听者,代码如下(StateChangeListener.java):

package com.test;
import java.util.EventListener;
public class StateChangeListener implements EventListener {
 
    public void handleEvent(MyEvent event) {
         System.out.println(event.toString() + " fire event " + event.getSourceMessage());
     }
}

按照要求,所有事件监听者要实现java.util.EventListener接口,这个接口是一个空的,只是一个标记(Tagging),习惯上会加一个handleEvent()方法,这个方法利用传递过来的事件消息进行相应处理。

好,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值