1. 程式人生 > >Java事件機制理解及應用

Java事件機制理解及應用

1.從總體看事件機制

其實事件機制是一種處理世界的方式和方法。傳統的順序程式設計總是按照流程來安排所做的工作,而事件機制的特點在於:等待,如果有事情發生則處理之。這樣的好處是順序程式設計在沒有事情做的時候也必須迴圈執行,做毫無效率的空的迴圈工作。而事件機制在沒有事情的時候則可以不做任何事情的等待,從而可以釋放各種資源用於其它需要的程式。其實,這和計算機的中斷處理是一個想法和道理的。

事件總是和某個物件相關,即每個事件必須有一個事件源。比如,按紐按下事件必須和某個按鈕相關,而絕對不會出現了一個按紐按下事件,但是沒有任何按鈕存在。

同時,某個事件發生了,則可能該事件會引起一些相關效果,也可能雖然發生,但不產生任何效果。即事件發生可能會被處理,也可能不會被處理。

處理一個事件的操作,可以由事件發生的事件源進行,而更多的可能是由其它物件來進行。比如,在一個視窗中的“退出”按鈕被按下,該事件引起視窗的關閉,這個關閉的操作必須由視窗,而不是該按鈕來進行。

事件機制中,操作事件發生後進程的主體並不會不斷地查詢事件是否發生,而應該等待事件源在事件發生時通知它該事件發生了。如視窗並不會不斷地查詢“退出”按鈕是否按下,而應該在“退出”按鈕按下事件發生時由該按鈕通過某種方式來通知視窗事件發生了。

對於事件源而言,需要知道其事件發生的主體可能沒有,可能有一個,也可能有多個。所以,當事件發生時,一般性地“說”:事件發生了,並給出事件發生的相關資訊是事件源的責任,但哪些主體需要得到該通知則不是事件源的責任,而是其它主體的責任。即:需要監控某個事件源事件是否發生的主體必須負責監聽事件源事件是否發生。

同一個事件源可以發生多種事件,同一類事件可以由不同的事件源引起。比如,按紐可以發生“按下”、“釋放”、“獲得焦點”等多個事件。而“獲得焦點”事件也可以由按鈕、窗體、列表框等多個事件源引起。

因此,事件處理機制必須表達和處理好這麼幾個東西:事件源,描述可能引起事件的物件的所有屬性,包括在事件發生時發出通知。事件,描述和處理事件的所有資訊。主體,負責對其關心的事件發生後的處理。事件監聽,負責監聽主體關心的事件源是否發生相關的事件,並在事件發生時將事件的資訊傳遞給主體。

2Java的事件處理機制概覽

根據事件處理機制的總體情況,Java從總體上採用了四個物件(類)來完成對事件的處理。

事件源類:描述事件發生源的基本屬性和行為。比如,按鈕是很多事件發生的事件源,

Java構造按鈕類來描述按鈕的形狀,顏色等等屬性以及在螢幕上繪製按鈕等動作,當然也包括按鈕按下等相關事件發生本身。同時,在事件發生時,事件源類還負責發出事件發生的通知。該行為通過事件源查詢自己的事件監聽者佇列,並將事件資訊通知佇列中的監聽者來文成。同時,事件源還在得到有關監聽者資訊時負責維護自己的監聽者佇列。

事件類:描述某個事件的所有屬性和相關動作。比如定義鍵盤事件類KeyEvent來描述鍵盤事件的所有資訊,如鍵是否按下、是否釋放、是否雙擊,以及相關鍵的資訊,如鍵碼,是否有組合鍵等等。

事件監聽者類,也就是關注事件的主體類:當事件發生後,該主體負責進行相關的事件處理,同時,它還負責通知相關的事件源,自己關注它的特定的事件,以便事件源在事件發生時能夠通知該主體。

事件監聽者介面:事件發生後,事件源要將相關的資訊通知對應的監聽者。這要求必須在事件源和監聽者之間定義一個標準的介面規範,以便完成這樣的資訊交換。監聽者介面正是負責定義這樣的介面規範。

這四種類的實現有以下一些比較關鍵的地方。

事件源的監聽者佇列的維護。通常可以通過定義一個可以接受任何物件的佇列來完成。因此,事件源應該至少做這麼三件事:定義佇列,通常通過定義一個Vector例項來接收和儲存Object型別的監聽者;定義新增監聽者的方法,通常通過定義由監聽者呼叫的addXXXListener方法完成向Vector佇列中新增監聽者;定義刪除監聽者的方法,通常通過定義由監聽者呼叫的removeXXXListener方法來刪除Vector佇列中記錄的監聽者。

事件源事件的通知。在事件源發生某個事件後,事件源構造相應的事件類的例項,並在監聽者佇列中查詢所有記錄的監聽者,並呼叫監聽者對應的事件處理函式從而達到通知監聽者的目的。這裡,為了順利地完成這種通知和呼叫,必須事先約定好這個處理函式介面。這種約定是由監聽者介面來進行的。即在監聽者介面中申明這些介面函式的名稱和引數,而由監聽者應用這些介面,並實現介面中的介面函式來完成。所以,介面函式實際上也就是監聽者的對應事件的處理函式,在事件發生後監聽者需要進行的操作都應該在這個函式中實現。同時,為了獲得事件的資訊,通常這樣的介面函式都會傳遞對應的事件類引數。當然,也可以在介面中定義其它需要傳遞的引數。事件源構造對應的事件例項,並呼叫介面程式完成引數傳遞和事件通知。因此,在事件源中,需要編寫相應的程式碼來完成事件佇列的查詢和介面函式的呼叫。

Java中,由於應用介面必須在應用的類中實現介面中的所有申明函式,有時對於不需要使用所有申明函式的監聽者比較麻煩,所以通常可以編寫一個基礎的介面卡類來應用介面,介面卡中預先實現所有的空介面函式,監聽者則通過繼承介面卡並重載自己需要的介面函式來避免直接應用介面的麻煩。

Java的類庫中,提供了大多數常用的事件源、事件類、介面類及介面卡類,因此實際使用中,只要在主體也就是監聽者中應用介面或介面卡,並實現相應的事件處理函式,然後利用addXXXListener新增相應的事件源的監聽器,就完成事件機制的使用了。

當然,如果編制了自己的新事件源類,並且需要實現在Java類庫中沒有預先實現的事件,則還需要編制自己的事件類(通常派生自EventObject),編制相應的事件介面類(通常派生自EventListener)並預定義相應的介面函式,在事件源類中實現相應的addXXXListener方法和removeXXXListener方法,並完成對監聽者佇列的管理和事件通知程式碼的編寫。

3.事件處理機制的聯想

其實,在事件發生時,事件源通知監聽者,其本質還是要在此時呼叫監聽者的相應處理函式。在CC++中,可以直接在事件源類中定義相應的處理函式指標,並在監聽者類中將事件源類的指標指向自己的相應函式就完成了。當然,如果要實現多個監聽者的監聽,也可以在事件源中定義函式指標佇列,並利用函式相應的函式來將相應監聽者類的函式指標賦給佇列元素,這樣的處理方式就和前述方式相似的。

事件類的更多的目的是封裝事件的相應資訊,並方便在基礎的事件類上的派生和重用。如果事件很簡單,並且不存在繼承等問題,其實可以不用構造事件類,直接簡單地在事件源類中給出相關的事件資訊就可以了。

同樣,介面類也是為了申明監聽者的事件處理函式的介面規範,並方面繼承和程式碼重用。如果監聽者固定且簡單,也可以直接在監聽者類中定義事件處理函式,而事件源直接呼叫就行了。

不過,專門定義事件類和介面類,能夠使事件處理機制規範化,並且對於程式碼重用很有好處。在CC++中,其實也可以按照類似的方式來考慮和組織事件處理機制。

4.事件處理機制的擴充套件應用

當我們定義我們自己的工具類庫時,完全可以參照上述機制來組織我們自己的事件處理。這裡,我們自己定義的類庫應該是我們的事件源,而以後使用這個類庫的應用程式則是監聽者。在類庫定義時,我們可以同時定義與該類庫相關的事件類來封裝事件的資訊,也同時定義相應的介面類來申明監聽者事件處理函式的介面規範,以及相應的介面卡類來減少應用介面的麻煩。當然,為了提高程式碼的重用性,並且考慮到Java的相關語法規定,上述四個類必須都申明為public,所以必須分別寫在各自與類名相同的檔案中,但應該申明為同一個包。

下面,我們以常見的計算工具為例,說明如何自己建立自己的事件處理機制。

考慮我們可能會建立很多各種不同的計算工具,比如常規的優化計算工具(各種優化方法),遺傳演算法計算工具,微粒群演算法計算工具等等。這些工具都是事件源,它們可能發生的事件包括:計算完成事件、計算放棄事件和單步計算完成事件(每計算完一步,但還沒有完成所有計算就發生該事件)。為了能夠方便這些計算工具的開發,我們可以組織一個所有這些計算工具的父類組織,包括抽象的計算類,計算事件類,計算事件介面類,計算事件介面卡類來搭建所有這些工具的計算事件處理框架。一旦框架完成,具體的計算工具類使用時我們就和使用比如Java類庫中的視窗、按鈕等類一樣,只需要應用程式中註冊監聽者,實現事件處理函式,然後進行計算就行了。具體的程式碼如下。

import java.util.*;

public class CalTst {//測試應用程式,即具體的監聽者

public static void main(String[] arg) {

System.out.println("Test Begin:");

myCal1 c1=new myCal1();//申明計算工具1的例項

c1.addCalListener(new myCal1Adapter());//註冊工具1的監聽者

c1.Run();//執行工具1

myCal2 c2=new myCal2();//申明工具2的例項

c2.addCalListener(new myAdaper());//註冊工具2監聽者

c2.Run();//執行工具2

}

}

class CalEvent extends EventObject {//計算工具事件類

public static final int STEPOVER=1;//申明事件標誌,單步計算完成

public static final int CALOVER=2;//計算完成標誌

public static final int CALCANCEL=3;//計算取消標誌

public static final int TYPEERROR=-1;

protected long StepNum;//單步計算的步數

protected int Type;//事件型別

public CalEvent(Object src) {//幾個事件建構函式

super(src);//登記事件源

Type=TYPEERROR;

}

public CalEvent(Object src, int mask) {

super(src);

if(mask==STEPOVER || mask==CALOVER || mask==CALCANCEL) Type=mask;

else Type=TYPEERROR;

}

public CalEvent(Object src, int mask, long step) {

super(src);

if(mask==STEPOVER || mask==CALOVER || mask==CALCANCEL) Type=mask;

else Type=TYPEERROR;

StepNum=step;

}

//一些實用方法

public void setType(int mask) { Type=mask; }

public void setType(int mask, long step){Type=mask; StepNum=step;}

public int getType() { return Type; }

public long getStepNum() { return StepNum; }

public boolean isStepCal() {

if(Type==CalEvent.STEPOVER) return true;

else return false;

}

public boolean isCalOver() {

if(Type==CalEvent.CALOVER) return true;

else return false;

}

public boolean isCalCancel() {

if(Type==CalEvent.CALCANCEL) return true;

else return false;

}

}

interface CalListener extends java.util.EventListener {//事件介面類

public boolean StepProformed(CalEvent event);//申明單步運算函式介面

public void CalOverProformed(CalEvent event);//申明計算完成函式介面

public void CancelProformed(CalEvent event); //申明計算取消函式介面

}

class CalAdapter implements CalListener {//事件介面卡類,實現3個空處理函式

public boolean StepProformed(CalEvent event){return true;}

public void CalOverProformed(CalEvent event){}

public void CancelProformed(CalEvent event){}

}

class Calculation {//計算類,實際的計算事件源

protected Vector listener;//監聽者佇列

public Calculation(){ listener=new Vector(); }

public synchronized void addCalListener(CalListener l) { listener.add(l); }//新增監聽者

public synchronized void removeCalListener(CalListener l){listener.remove(l);}

public boolean notifyEvent(int mask) {//事件通知函式過載版本1

Vector l=new Vector();

l=(Vector)listener.clone();

boolean rt=true;

CalEvent ev=new CalEvent(this);

if(mask==CalEvent.STEPOVER) ev.setType(CalEvent.STEPOVER,0);

else ev.setType(mask);

synchronized(this) {//多執行緒鎖定

for(int i=0; i<l.size(); i++) {//查詢監聽者,並呼叫處理函式

if(ev.isStepCal()) rt=((CalListener)l.elementAt(i)).StepProformed(ev);

else if(ev.isCalOver()) ((CalListener)l.elementAt(i)).CalOverProformed(ev);

else if(ev.isCalCancel()) ((CalListener)l.elementAt(i)).CancelProformed(ev);

}

}

return rt;

}

public boolean notifyEvent(int mask, long step) {//事件通知函式過載版本2

Vector l=new Vector();

l=(Vector)listener.clone();

boolean rt=true;

CalEvent ev=new CalEvent(this);

if(mask==CalEvent.STEPOVER) ev.setType(CalEvent.STEPOVER,step);

else ev.setType(mask);

synchronized(this) {

for(int i=0; i<l.size(); i++) {

if(ev.isStepCal()) rt=((CalListener)l.elementAt(i)).StepProformed(ev);

else if(ev.isCalOver()) ((CalListener)l.elementAt(i)).CalOverProformed(ev);

else if(ev.isCalCancel()) ((CalListener)l.elementAt(i)).CancelProformed(ev);

}

}

return rt;

}

}

class myCal1 extends Calculation {//計算工具1

public void Run() {//執行工具1方法

for(int i=0; i<5; i++) notifyEvent(CalEvent.STEPOVER,i);//產生單步事件

notifyEvent(CalEvent.CALOVER);//產生計算完成事件

}

public String getResult(){ return "OK"; }//返回計算完成結果

}

class myCal1Adapter extends CalAdapter {//計算工具1介面卡

public boolean StepProformed(CalEvent e) { //單步事件處理函式

System.out.println("Step "+e.getStepNum());

return true;

}

public void CalOverProformed(CalEvent e) { //計算完成處理函式

System.out.println("The Result is "+((myCal1)e.getSource()).getResult());

}

}

class myCal2 extends Calculation {//計算工具2

public void Run() {//計算工具2執行

notifyEvent(CalEvent.CALOVER);//產生計算完成事件

}

}

class myAdaper extends CalAdapter {//計算工具2介面卡

public void CalOverProformed(CalEvent e) {//計算完成處理函式

System.out.println("The Source is "+e.getSource().toString());

}

}

執行上述例程,可以獲得如下結果:

Test Begin:

Step 0

Step 1

Step 2

Step 3

Step 4

The Result is OK

The Source is [email protected]

可以看出,應用程式利用註冊的監聽器及其事件處理函式,完全獲得了計算事件對應的執行結果。這種事件處理框架完全可以應用於我們自己的計算類工具庫中。

相關推薦

Java事件機制理解應用

1.從總體看事件機制 其實事件機制是一種處理世界的方式和方法。傳統的順序程式設計總是按照流程來安排所做的工作,而事件機制的特點在於:等待,如果有事情發生則處理之。這樣的好處是順序程式設計在沒有事情做的時候也必須迴圈執行,做毫無效率的空的迴圈工作。而事件機制在沒有事情的時候則可

grep之正則表達式的理解應用

grep 正則表達式在本周學習中是個難點和重點,其中難免會有很多坑,也難免會不停的往裏跳,當跳的比較多了也就長記性了,通過很多次練習慢慢也就能發現其中暗藏玄機,成功的避開大坑選擇往小坑裏跳了,我相信在以後的學習中會不斷進步、勤加練習終究會跳出來的。好了,以下是本人對正則表達式的一點理解,如有錯誤之處請聯系我

Java 之IO流應用

生成 介紹 lena 刷新 [0 規律 exceptio closed 形式參數 IO流 IO流概述及FileWriter類的使用 FileReader類使用 緩沖流介紹和使用 IO流相關案例 NO.one IO流概述及FileWriter類使用

css行高line-height的一些深入理解應用

out spa 行高 定義 blank 分享 tac 而且 -s 聲明:此文為轉載,點擊查看原文,原文發布日期為2009年,僅供大家參考,如有侵權24小時內刪除,聯系QQ:1522025433。 一、前言 前兩天在騰訊ISD團隊博客上看到一篇翻譯的文章“深入理解css 行高

Java反射機制的簡單應用

mod arc pos ret system containe java反射機制 track san 一直感覺java的反射機制非常強大,可是可用的地方不多。在android學習的時候。一直想實現掛斷電話的功能,可是

淺談對xmpp的理解應用

mpp 通信 new xmpp times div log 傳輸數據 重新 參考原文鏈接 http://blog.sina.com.cn/s/blog_69f68f880102uyeg.html 一、xmpp是基於xml的協議。具有遵循標準,有安全性,使用TCP傳的xml的

理解應用 Oracle 12c 插拔數據庫

src session alt obj 結構 rtu head code oot 一、概述 1、Oracle 12c 可插拔數據庫體系結構 Oracle 12c 中引入了一個新功能就是Oracle Multitenant,這個功能可以在多租戶容器數據庫中,創建並維護許多個

狀態機理解應用

nsh 處理 .html 應用場景 logs color tps details pan 今天看nginx講解,看到在處理http請求行的時候用的是狀態機,一直淺顯的一位就是if else 或者switch,雖然實現是這種方式,但是內含的意義可不止這麽簡單,就再貼點別人的理

EIGRP路由協議的簡單理解應用

1.EIGRP 增強型內部閘道器路由協議 他是動態路由協議,是思科私有的路由協議(2013年已經公有化) 特點:     1)路由更新:閃速更新;觸發式更新;路由增量更新       2)協議更新採用組播地址來維持EIGRP的路由資訊傳遞;具有固定的組播地址來提供EIGRP通訊       

Oracel資料庫中檢視與同義詞的理解應用場景

轉載至: https://blog.csdn.net/u012411219/article/details/51321162 1. 資料庫物件之【檢視】簡單介紹    1.1 What:什麼叫檢視?          

職責鏈初步理解應用小demo

什麼是職責鏈 先看個需要用到職責的場景: if(請假天數 <= 1){ askForLeave(小組長); }else if(請假天數 <= 3 && 請假天數 > 1){ askForLeave(專案經理); }else if(請假天數 &

Spring的事件監聽應用

最近公司在重構廣告系統,其中核心的打包功由廣告系統呼叫,即對apk打包的呼叫和打包完成之後的回撥,需要提供相應的介面給廣告系統。因此,為了將apk打包的核心流程和對接廣告系統的業務解耦,利用了spring的事件監聽特性來滿足需求。以下說明spring的事件機制的相關內容。   1.觀察

單例模式的理解應用

單例模式 單例模式定義:定義:確保某個類只有一個例項,而且自行例項化提供給外部使用。 單例模式有很中比較常用的有懶漢模式和餓漢模式。注:我在網上查說的比較多的模式,在專案中比較常看到的有懶漢模式。餓漢模式沒怎麼看過。 懶漢模式: public c

JavaScript事件冒泡簡介應用

一、什麼是事件冒泡 在一個物件上觸發某類事件(比如單擊onclick事件),如果此物件定義了此事件的處理程式,那麼此事件就會呼叫這個處理程式,如果沒有定義此事件處理程式或者事件返回true,那麼這個事件會向這個物件的父級物件傳播,從裡到外,直至它被處理(父級物件

CAS演算法的理解應用

應用 眾所周知,Java中有許多執行緒安全類,比如執行緒安全的集合類。從Java5開始,在java.util.concurrent包下提供了大量支援高效併發訪問的集合介面和實現類。如:ConcurrentMap、ConcurrentLinkedQueue等執行緒安全集合。 引入問題 那麼問題

Canal( 增量資料訂閱與消費 )的理解應用

canal是阿里巴巴旗下的一款開源專案,純Java開發。基於資料庫增量日誌解析,提供增量資料訂閱&消費,目前主要支援了MySQL(也支援mariaDB)。 起源:早期,阿里巴巴B2B公司因為存在杭州和美國雙機房部署,存在跨機房同步的業務需求。不過早期的資料庫同步業務,主要是基於trigger的方式獲

line-height的一些深入理解應用

“行高”顧名思意指一行文字的高度。具體來說是指兩行文字間基線之間的距離。 下圖的紅色線即為基線。 一. line-height與line boxes高度 ss中起高度作用的應該就是height以及line-height了,如果一個標籤沒有定義heigh

1. java事件機制包括哪三個部分?分別介紹。

java事件機制包括三個部分:事件、事件監聽器、事件源。 1、事件。一般繼承自java.util.EventObject類,封裝了事件源物件及跟事件相關的資訊。 com.javaedu.event.CusEvent類 Java程式碼 1. packag

數字貨幣開發專題(區塊鏈原理理解應用例項)

區塊鏈愛好者(QQ:53016353) 一、區塊鏈 X原理理解 1、位元資產的建立: 在區塊鏈 X系統中,位元資產的建立,必須有一方買入一方賣空才能發生。 買方b提交了買單,以0.01區塊鏈的單價買入BitUSD,如果系統內其他人覺得出價太低,這個買單不會成交。如果大叔a

[java][db]JAVA分散式事務原理應用

JTA(Java Transaction API)允許應用程式執行分散式事務處理--在兩個或多個網路計算機資源上訪問並且更新資料。JDBC驅動程式的JTA支援極大地增強了資料訪問能力。   本文的目的是要提供一個關於的Java事務處理API(JTA)的高階的概述,以及與分散