事件機(jī)制的三個(gè)角色
- 事件源叭爱,表示事件發(fā)生的起源
- 事件對象,持有一個(gè)事件源
- 事件處理的監(jiān)聽器办悟,事件發(fā)生時(shí)具體的處理回調(diào)捺氢,需要用戶去實(shí)現(xiàn)這個(gè)接口
在Java AWT中牵敷,事件機(jī)制廣泛應(yīng)用。我們將模仿點(diǎn)擊事件椿息,構(gòu)建完整的源->觸發(fā)->處理過程歹袁。UML類圖如下:
首先,創(chuàng)建一個(gè)事件對象寝优。
import java.util.EventObject;
public class ClickEvent extends EventObject {
private EventSource src;
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public ClickEvent(EventSource source) {
super(source);
this.src = source;
}
}
ClickEvent
繼承自EventObject
条舔,持有一個(gè)EventSource
的引用,在構(gòu)造點(diǎn)擊事件時(shí)必須指明事件源乏矾。
事件源定義:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
public class EventSource {
private Semaphore semaphore = new Semaphore(1);
private final List<ClickEventListener> listeners = new ArrayList<>();
public void addListener(ClickEventListener listener) throws InterruptedException {
semaphore.acquire(1);
listeners.add(listener);
semaphore.release(1);
}
public void removeListener(ClickEventListener listener) throws InterruptedException {
semaphore.acquire(1);
if(!listeners.isEmpty())
listeners.remove(listener);
semaphore.release(1);
}
protected void actionPerformed() throws InterruptedException {
semaphore.acquire(1);
ClickEvent event = new ClickEvent(this);
for (ClickEventListener listener : listeners) {
listener.click(event);
}
semaphore.release(1);
}
}
事件源可以添加一組監(jiān)聽器逞刷,綁定的一組監(jiān)聽器在事件觸發(fā)之后,會(huì)將監(jiān)聽器的具體動(dòng)作逐一執(zhí)行妻熊。
定義一個(gè)簡單的點(diǎn)擊事件監(jiān)聽器:
public interface ClickEventListener extends EventListener {
void click(ClickEvent e);
}
ClickEventListener
繼承自EventListener
夸浅,查看源碼發(fā)現(xiàn)EventListener
是一個(gè)空接口,因此定義的事件監(jiān)聽器將是一個(gè)SAM interface扔役,如果還不清楚SAM interface的概念帆喇,請查看我之前的一篇文章Functional Programming in Java 8,因此可以使用lambda表達(dá)式來實(shí)現(xiàn)這個(gè)監(jiān)聽器接口亿胸。
最后坯钦,我們需要完成一次完整的調(diào)用處理:
public class Main {
public static void main(String[] args) {
EventSource source = new EventSource();
try {
source.addListener((e) -> System.out.println("Click event performed!"));
source.actionPerformed();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
事件處理機(jī)制在某種程度上與發(fā)布-訂閱模式非常相似,事件監(jiān)聽器的角色與觀察者類似侈玄,事件源則充當(dāng)了被觀察對象婉刀。事件源狀態(tài)觸發(fā)后,主動(dòng)發(fā)起通知給監(jiān)聽器序仙,監(jiān)聽器完成各種后續(xù)處理突颊。