第一節的範例過於簡單《從零開始理解JAVA事件處理機制(1)》,簡單到讓大家覺得這樣的程式碼簡直毫無用處。但沒辦法,我們要繼續寫這毫無用處的程式碼,然後引出下一階段真正有益的程式碼。
一:事件驅動模型初窺
我們要說事件驅動模型是觀察者模式的升級版本,那我們就要說說其中的對應關係:
觀察者對應監聽器(學生)
被觀察者對應事件來源(教師)
事件來源產生事件,事件帶有事件源,監聽器監聽事件。愛鑽牛角尖的朋友可能會說,我擦,什麼叫產生事件,監聽事件,事件事件到底什麼?
莫慌,如果我們用程式碼來說事,事件它就是個類,事件來源也是個類別。這裡面一共牽扯到四個類,事件來源(即教師、即被觀察者)、事件(是一個類,見下文,一般我們以Event或EventObject命名結尾)、監聽器介面、具體的監聽器(即學生、即觀察者)。
就像我們上一篇文章中的第一節提到的一樣,JDK中當然有現成的事件模型類,我們不妨來一個一個的查看一下吧。
首先看監聽器(即學生、即觀察者,大家不要嫌我煩,不停滴括號提醒,這是為了不停滴給大家加深印象),
package java.util;
/**
簡單到不能再簡單了,對吧,甚至連一個聲明的方法都沒有,那它存在的意義在哪?還記得物件導向中的上溯造型嗎,所以它的意義就在於告訴所有的呼叫者,我是一個監聽器。
* 所有事件監聽器介面都必須擴充的標記介面。*/
public interface EventListener {
}
再來看看事件,也就是Event或EventObject結尾的那個類,裡面含有getSource方法,回傳的就是事件來源(即教師、即被觀察者),
package java.util;/**
** 所有事件狀態物件都應從中派生的根類別。 source",
# /**
* 邏輯上被認為是相關事件最初發生的物件
* 最初發生的物件。
*
* @since JDK1.1
*/
public class EventObject implements java.io.Serializable {
private static final long serialVersionUID = 5516075349620653480* 事件最初發生的物件。 */
protected transient Object source; /*** 建構一個原型事件。 */
@return The object on which the Event initially occurred.
public == null)
throw new IllegalArgumentException("null source");*/
public Object getSource() {
return source #) {
## 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 HomeworkEventObject extends java.util.EventObject {package com.zuikc. events;
public class Student implements HomeworkListener{
private String name;
public Student(String name){
## public void update(HomeworkEventObject o, Object arg) {
Teacher teacher = o.getTeacher();
System.out.printf("%)%)觀察到實際安排通知了作業《%s》 \n", this.name, teacher.getName(), arg);
}
}對比上篇,有變動沒?
# public HomeworkEventObject(Object source) {
super(source);}
public HomeworkEventObject(Teachereach遠Teacher getTeacher( ){return (Teacher) super.getSource();
package com.zuikc.events;
}
}
#在這個類別中,指的關注的就是這個getTeacher方法,它封裝了父類別EventObject的getSource方法,得到了事件來源。理論上,我們使用父類別的getSource方法也可行,但是重新在子類別封裝一下,可讀性更強一點。
然後呢,然後就是我們的教師類,教師類就是事件源,如下:import java.util .*;
public class Teacher {
private String name;private List第二處,在觀察者模式中,我們直接呼叫Observable的notifyObservers來通知被觀察者,現在我們只能靠自己了,於是我們看到了這段程式碼,# for (HomeworkListener listener : homeworkListenerList) {homeworks; /* ## 的列表,為什麼?
* 在觀察者模式中,教師是被觀察者,繼承自java.util.Observable,Observable包含了這個清單* 現在我們沒有這個清單了,所以要自己建立一個
# * /private Set
* 觀察者模式中,我們直接為Observable的notifyObserver ## for (HomeworkListener listener : homeworkListenerList) {homeworkListenerList;
public String getName() {
return this.name;#. # this.name = name;
this.homeworks = new ArrayList();
public void setHomework (String homework) {
System.out.printf("%s佈置作業了%s \n", this.name, homework);
homeworks HomeworkEventObject(this);
/*listener.update(event, homework
}
public void addObserver(HomeworkListener homeworkListener){
homeworkListenerList.add(homeworkListener);## #>那麼一點點,有幾個地方值得注意:第一個地方,Teacher沒有父類別了,Teacher作為事件中的事件來源Source被封裝到HomeworkEventObject中了。這沒有什麼不好的,業務物件和框架程式碼隔離開來,解耦的非常好,但是正因為如此,我們需要在Teacher中自己維護一個Student的列表,於是,我們看到了homeworkListenerList這個變數。
listener.update(event, homework);import java.util.EventListener;public class Client {}
這一點問題也沒有,我們繼續來看客戶端程式碼吧:
package com.zuikc.events;## public static void main(String[ ] args) {2:在事件模型中,每個監聽者(觀察者)都需要實作一個自己的介面。沒錯,看看我們的滑鼠事件,分錶就有點擊、雙擊、移動等等的事件,這分別就是增加了程式碼的彈性;不管怎麼說,我們用一堆小白程式碼實作了一個事件驅動模型的範例,雖然沒什麼實際用處,但也解釋了原理,接下來的一節,我們就要看看那些稍微複雜且看上去很有用的程式碼了!Student student1= new Student("張三");
Student student2 = new Student("李四");# teacher1.addObserver(student1);
teacher1.addObserver(student2);S;
##結果如下:
從客戶端的角度來說,我們幾乎完全沒有更改任何地方,跟觀察者模式的客戶端程式碼一模一樣,但是內部在的實作機制上,我們卻使用了事件機制。
現在我們來總結下,觀察者模式和事件驅動模型的幾個不同點:1:事件來源不再繼承任何模式或模型本身的父類,徹底將業務程式碼解耦出來;
以上是從零開始理解JAVA事件處理機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!