用java實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制

由于項(xiàng)目需求岔冀,需要為Java提供一套支持事件驅(qū)動(dòng)機(jī)制的類庫(kù)偎快,可以實(shí)現(xiàn)類似于C#中的event和delegate機(jī)制。眾所周知目代,Java語(yǔ)言本身以及其標(biāo)準(zhǔn)庫(kù)中并沒(méi)有提供事件驅(qū)動(dòng)機(jī)制的相關(guān)接口焚刚,雖然Swing(我且認(rèn)為其不屬于標(biāo)準(zhǔn)庫(kù)点弯,因?yàn)橐话銢](méi)人用:)中存在相關(guān)的類支持該機(jī)制以實(shí)現(xiàn)組件的事件處理,但它畢竟是與GUI相耦合的矿咕,而在其它類型的應(yīng)用程序中使用起來(lái)顯得就有些別扭抢肛,缺乏通用性狼钮。因此有必要實(shí)現(xiàn)一套通用的Java事件驅(qū)動(dòng)機(jī)制類庫(kù),然后將其應(yīng)用于通用的Java應(yīng)用程序當(dāng)中捡絮,雖然這并不是什么難事:)

讓我們先考察一下C#的事件驅(qū)動(dòng)機(jī)制編寫(xiě)方法熬芜。C#中提供的event關(guān)鍵字可以很容易的用來(lái)定義一個(gè)事件,然后通過(guò)向事件中添加事件處理函數(shù)(在C#中一般用委托(delegate)來(lái)引用一個(gè)函數(shù))福稳,觸發(fā)事件就可以調(diào)用相關(guān)的處理函數(shù)涎拉,也即是事件驅(qū)動(dòng)的過(guò)程。例如:

//定義事件和對(duì)應(yīng)的委托
public event MyDelegate Click;
public delegate void MyDelegate();

//定義委托
void OnClick(){
    console.writeline("you just clicked me!");
}

//將委托與事件關(guān)聯(lián)
Click += OnClick;

//觸發(fā)事件
Click();

上面的代碼就是用C#實(shí)現(xiàn)的事件驅(qū)動(dòng)機(jī)制的一個(gè)簡(jiǎn)單的例子的圆,可見(jiàn)是非常簡(jiǎn)單的鼓拧,這都源于C#在語(yǔ)言層面(其實(shí)是CLR)提供的便利。遺憾的是Java并不提供這樣的便利越妈,需要人為去實(shí)現(xiàn)季俩。下面本文將提供兩種實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制的方法,僅供參考梅掠。

  1. 觀察者模式

觀察者模式是一種常用的設(shè)計(jì)模式酌住,觀察者(Observer)先通過(guò)訂閱被觀察對(duì)象(Subject),這樣一旦被觀察者(Subject)發(fā)生某種變化阎抒,就會(huì)將變化通知觀察者(Observer)赂韵。

這種設(shè)計(jì)模式剛好可以用于事件驅(qū)動(dòng)機(jī)制,事件(event)相當(dāng)于被觀察對(duì)象(Subject)挠蛉,一旦事件被觸發(fā),就會(huì)調(diào)用事件處理函數(shù)肄满,可見(jiàn)事件處理函數(shù)(C#中的委托)可以看作是觀察者谴古。因此可以像如下這樣實(shí)現(xiàn)上文中的功能。

/*事件類*/
public Event {
    //與事件相關(guān)的事件處理函數(shù)
    public ArrayList<Callback> callbackList;
    
    //事件觸發(fā)函數(shù)
    public void emit(){
        for(Callback cb : callbackList){
            cb.run();
        }
    }
    
    //注冊(cè)事件處理函數(shù)
    public registerCallback(Callback cb){
        callbackList.add(cb);
    }
}

/*事件處理函數(shù)類*/
public interface Callback {
    void run();
}

public OnClick implements Callback {
    //函數(shù)
    public void run(){
        System.out.println("you just clicked me!");
    }
    
    
/*實(shí)現(xiàn)事件驅(qū)動(dòng)*/
Event e = new Event();  
//將OnClick事件處理函數(shù)注冊(cè)到事件中
e.registerCallback(new OnClick()); 
//觸發(fā)事件
e.emit();

上面的Java代碼實(shí)現(xiàn)了一種簡(jiǎn)單的事件驅(qū)動(dòng)機(jī)制稠歉,原理很簡(jiǎn)單掰担,是一種典型的觀察者模式的應(yīng)用案例。

  1. 利用反射

Java語(yǔ)言提供強(qiáng)大的反射功能怒炸,可以在運(yùn)行時(shí)獲取類的各個(gè)組成部分(比如類名带饱、類成員函數(shù)、類屬性等等)并對(duì)其進(jìn)行操作阅羹。下面使用反射來(lái)實(shí)現(xiàn)簡(jiǎn)單的事件驅(qū)動(dòng)機(jī)制勺疼。

/*事件處理類*/
public class EventHandler {
    //事件源
    private Object sender;
    //事件處理函數(shù)名稱(用于反射)
    private String callback;
    
    public EventHandler(Object sender, String callback){
        this.sender = sender;
        this.callback = callback;
    }
    
    //事件觸發(fā)
    public void emit(){
    Class senderType = this.sender.getClass();
    try {
        //獲取并調(diào)用事件源sender的事件處理函數(shù)
        Method method = senderType.getMethod(this.callback);
        method.invoke(this.sender);
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }
}


/*事件源*/
public class Button(){
    /*可以在此設(shè)置Button類的相關(guān)屬性,比如名字等*/
    private String name;
    ...
    
    
    //事件處理函數(shù)
    public void onClick(){
        System.out.println("you just clicked me!");
    }
}
    
    
/*實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制*/
Button b = new Button();
if(/*收到按鈕點(diǎn)擊信號(hào)*/){
    EventHandler e = new EventHandler(b, "onClick");
    e.emit();
}

上述代碼展示了利用反射實(shí)現(xiàn)的事件驅(qū)動(dòng)機(jī)制捏鱼,利用反射機(jī)制的好處是其具有強(qiáng)大的擴(kuò)展性执庐,比如我的事件處理函數(shù)中可以引入一個(gè)EventArgs的形參,從而可以讓事件本身帶有參數(shù)导梆,這樣就可以讓事件攜帶更多的信息轨淌,改寫(xiě)后的事件處理函數(shù)如下方的代碼所示:

public class EventArgs {
    //參數(shù)
    String p1;
    Integer p2;
    ...
    
}

//onClick事件處理函數(shù)改寫(xiě)
public void onClick(Object sender, EventArgs e){
    //參數(shù)e提供更多的信息
    System.out.println("Hello, you clicked me! " + e.p1 + e.p2);
}

//觸發(fā)函數(shù)emit改寫(xiě)
public void emit(EventArgs e){
Class senderType = this.sender.getClass();
try {
    //獲取并調(diào)用事件源sender的事件處理函數(shù)
    Method method = senderType.getMethod(this.callback, this.getClass(), e.getClass());
    method.invoke(this.sender, this.sender, e);
    } catch (Exception e2) {
        e2.printStackTrace();
    }
}

是不是似曾相識(shí)迂烁?沒(méi)錯(cuò),和用C#寫(xiě)Winform窗體時(shí)递鹉,Visual studio為你自動(dòng)生成的事件處理函數(shù)(代碼中的onClick函數(shù))幾乎具有完全相同的形式盟步,但此時(shí)我們是用Java實(shí)現(xiàn)的。

當(dāng)然躏结,除了以上提到的兩種方法可以實(shí)現(xiàn)Java的事件驅(qū)動(dòng)機(jī)制以外却盘,還有一些其它的方法,比如可以利用Java的內(nèi)部類來(lái)實(shí)現(xiàn)窜觉,筆者也曾寫(xiě)過(guò)一些示例代碼谷炸,這里就不再冗言了,留待以后再講禀挫。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末旬陡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子语婴,更是在濱河造成了極大的恐慌描孟,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砰左,死亡現(xiàn)場(chǎng)離奇詭異匿醒,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)缠导,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)廉羔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人僻造,你說(shuō)我怎么就攤上這事憋他。” “怎么了髓削?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵竹挡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我立膛,道長(zhǎng)揪罕,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任宝泵,我火速辦了婚禮好啰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鲁猩。我一直安慰自己坎怪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布廓握。 她就那樣靜靜地躺著搅窿,像睡著了一般嘁酿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上男应,一...
    開(kāi)封第一講書(shū)人閱讀 52,736評(píng)論 1 312
  • 那天闹司,我揣著相機(jī)與錄音,去河邊找鬼沐飘。 笑死游桩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的耐朴。 我是一名探鬼主播借卧,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼筛峭!你這毒婦竟也來(lái)了铐刘?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤影晓,失蹤者是張志新(化名)和其女友劉穎镰吵,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體挂签,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疤祭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了饵婆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勺馆。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖侨核,靈堂內(nèi)的尸體忽然破棺而出谓传,到底是詐尸還是另有隱情,我是刑警寧澤芹关,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站紧卒,受9級(jí)特大地震影響侥衬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜跑芳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一轴总、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧博个,春花似錦怀樟、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)械荷。三九已至,卻和暖如春虑灰,著一層夾襖步出監(jiān)牢的瞬間吨瞎,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工穆咐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颤诀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓对湃,卻偏偏與公主長(zhǎng)得像崖叫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拍柒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,332評(píng)論 25 707
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法心傀,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法斤儿,繼承相關(guān)的語(yǔ)法剧包,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,667評(píng)論 18 399
  • 從15年末開(kāi)始在豆瓣關(guān)注三公子的理財(cái)文章往果,到現(xiàn)在已經(jīng)經(jīng)歷了兩年時(shí)間疆液,由當(dāng)初的雄心壯志,到現(xiàn)在的毫無(wú)改變陕贮,可以說(shuō)時(shí)間...
    素人漁女閱讀 479評(píng)論 0 2
  • 加入自控力讀寫(xiě)群肮之,初衷是讓自己堅(jiān)持日更掉缺,不管寫(xiě)什么?必須從保持狀態(tài)開(kāi)始戈擒,因?yàn)槲疑钪@種狀態(tài)的改變會(huì)帶動(dòng)更多的變化眶明。...
    京珂大師姐閱讀 304評(píng)論 18 15
  • 今天的文章介紹了古典老師的新書(shū),恰好書(shū)也到手了筐高∷汛眩看到有個(gè)小伙伴說(shuō),“有點(diǎn)失望柑土,基本是公眾號(hào)文章的集合”蜀肘。當(dāng)時(shí)我就笑...
    拉面的第二人生閱讀 457評(píng)論 0 51