您好,登錄后才能下訂單哦!
由于項目需求,需要為Java提供一套支持事件驅動機制的類庫,可以實現類似于C#中的event和delegate機制。眾所周知,Java語言本身以及其標準庫中并沒有提供事件驅動機制的相關接口,雖然Swing(我且認為其不屬于標準庫,因為一般沒人用:)中存在相關的類支持該機制以實現組件的事件處理,但它畢竟是與GUI相耦合的,而在其它類型的應用程序中使用起來顯得就有些別扭,缺乏通用性。因此有必要實現一套通用的Java事件驅動機制類庫,然后將其應用于通用的Java應用程序當中,雖然這并不是什么難事:)
讓我們先考察一下C#的事件驅動機制編寫方法。C#中提供的event關鍵字可以很容易的用來定義一個事件,然后通過向事件中添加事件處理函數(在C#中一般用委托(delegate)來引用一個函數),觸發事件就可以調用相關的處理函數,也即是事件驅動的過程。例如:
//定義事件和對應的委托 public event MyDelegate Click; public delegate void MyDelegate(); //定義委托 void OnClick(){ console.writeline("you just clicked me!"); } //將委托與事件關聯 Click += OnClick; //觸發事件 Click();
上面的代碼就是用C#實現的事件驅動機制的一個簡單的例子,可見是非常簡單的,這都源于C#在語言層面(其實是CLR)提供的便利。遺憾的是Java并不提供這樣的便利,需要人為去實現。下面本文將提供兩種實現事件驅動機制的方法,僅供參考。
觀察者模式
觀察者模式是一種常用的設計模式,觀察者(Observer)先通過訂閱被觀察對象(Subject),這樣一旦被觀察者(Subject)發生某種變化,就會將變化通知觀察者(Observer)。
這種設計模式剛好可以用于事件驅動機制,事件(event)相當于被觀察對象(Subject),一旦事件被觸發,就會調用事件處理函數,可見事件處理函數(C#中的委托)可以看作是觀察者。因此可以像如下這樣實現上文中的功能。
/*事件類*/ public Event { //與事件相關的事件處理函數 public ArrayList<Callback> callbackList; //事件觸發函數 public void emit(){ for(Callback cb : callbackList){ cb.run(); } } //注冊事件處理函數 public registerCallback(Callback cb){ callbackList.add(cb); } } /*事件處理函數類*/ public interface Callback { void run(); } public OnClick implements Callback { //函數 public void run(){ System.out.println("you just clicked me!"); } /*實現事件驅動*/ Event e = new Event(); //將OnClick事件處理函數注冊到事件中 e.registerCallback(new OnClick()); //觸發事件 e.emit();
上面的Java代碼實現了一種簡單的事件驅動機制,原理很簡單,是一種典型的觀察者模式的應用案例。
利用反射
Java語言提供強大的反射功能,可以在運行時獲取類的各個組成部分(比如類名、類成員函數、類屬性等等)并對其進行操作。下面使用反射來實現簡單的事件驅動機制。
/*事件處理類*/ public class EventHandler { //事件源 private Object sender; //事件處理函數名稱(用于反射) private String callback; public EventHandler(Object sender, String callback){ this.sender = sender; this.callback = callback; } //事件觸發 public void emit(){ Class senderType = this.sender.getClass(); try { //獲取并調用事件源sender的事件處理函數 Method method = senderType.getMethod(this.callback); method.invoke(this.sender); } catch (Exception e2) { e2.printStackTrace(); } } } /*事件源*/ public class Button(){ /*可以在此設置Button類的相關屬性,比如名字等*/ private String name; ... //事件處理函數 public void onClick(){ System.out.println("you just clicked me!"); } } /*實現事件驅動機制*/ Button b = new Button(); if(/*收到按鈕點擊信號*/){ EventHandler e = new EventHandler(b, "onClick"); e.emit(); }
上述代碼展示了利用反射實現的事件驅動機制,利用反射機制的好處是其具有強大的擴展性,比如我的事件處理函數中可以引入一個EventArgs的形參,從而可以讓事件本身帶有參數,這樣就可以讓事件攜帶更多的信息,改寫后的事件處理函數如下方的代碼所示:
public class EventArgs { //參數 String p1; Integer p2; ... } //onClick事件處理函數改寫 public void onClick(Object sender, EventArgs e){ //參數e提供更多的信息 System.out.println("Hello, you clicked me! " + e.p1 + e.p2); } //觸發函數emit改寫 public void emit(EventArgs e){ Class senderType = this.sender.getClass(); try { //獲取并調用事件源sender的事件處理函數 Method method = senderType.getMethod(this.callback, this.getClass(), e.getClass()); method.invoke(this.sender, this.sender, e); } catch (Exception e2) { e2.printStackTrace(); } }
是不是似曾相識?沒錯,和用C#寫Winform窗體時,Visual studio為你自動生成的事件處理函數(代碼中的onClick函數)幾乎具有完全相同的形式,但此時我們是用Java實現的。
當然,除了以上提到的兩種方法可以實現Java的事件驅動機制以外,還有一些其它的方法,比如可以利用Java的內部類來實現,筆者也曾寫過一些示例代碼,這里就不再冗言了,留待以后再講。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。