對於事件的概念我想第一次的接觸莫過於UI上的元件,例如當點擊按鈕後要在Label上顯示某些字樣。但在很多實務上我們也有自訂事件監聽者與發送事件的必要,如某個元件做了選擇,而在另一個元件上會接收到這個選擇事件,這種客製的行為就需要透過自訂事件。在這邊會舉個範例一步步看如何做到
#Device interface
public interface IDevice {
public String getName();
public Status getStatus();
public void init();
public void open();
public void runing();
public void close();
public void dispose();
}
#抽象Device
public abstract class Device implements IDevice{
private String name;
private Status status;
public Device(String name) {
this.name = name;
init();
}
@Override
public void init() {
System.out.println(getName()+" is initializing");
setStatus(Status.INITIALIZAE);
}
@Override
public void open() {
System.out.println(getName()+" is opened");
setStatus(Status.OPEN);
}
@Override
public void runing() {
System.out.println(getName()+" is running");
setStatus(Status.RUNNING);
}
@Override
public void close() {
System.out.println(getName()+" is closed");
setStatus(Status.CLOSE);
}
@Override
public void dispose() {
}
@Override
public String toString() {
return getName();
}
@Override
public String getName() {
return "'"+name+"'";
}
@Override
public Status getStatus() {
return status;
}
private void setStatus(Status status) {
this.status = status;
}
}
#Status
public enum Status {
INITIALIZAE, OPEN, RUNNING, CLOSE;
}
#事件觸發者 (Controller)
Controller繼承Device,在呼叫open及close時會利用StatusEventManager來發送一個StatusEvent的事件
public class Controller extends Device{
public Controller(String name) {
super(name);
// TODO Auto-generated constructor stub
}
@Override
public void open() {
super.open();
StatusEventManager.getInstance().dispatchStatusUpdate(new StatusEvent(this));
}
@Override
public void close() {
super.close();
StatusEventManager.getInstance().dispatchStatusUpdate(new StatusEvent(this));
}
}
Controller繼承Device,在呼叫open及close時會利用StatusEventManager來發送一個StatusEvent的事件
#事件監聽者 (Receiver)
Receiver除了繼承Device外,還另外實作了StatusListener,在初始化時呼叫StatusEventManager註冊其為監聽者! 而在監聽到事件後會在updateStatus上做相對的行為
public class Receiver extends Device implements StatusListener{
public Receiver(String name) {
super(name);
// TODO Auto-generated constructor stub
StatusEventManager.getInstance().addListener(this);
}
@Override
public void updateStatus(StatusEvent event) {
// TODO Auto-generated method stub
Object source = event.getSource();
if(source instanceof IDevice) {
IDevice control = (IDevice) source;
if(control.getStatus() == Status.OPEN) {
runing();
}else if(control.getStatus() == Status.CLOSE) {
close();
}
System.out.println("======================================================");
}
}
@Override
public void dispose() {
// TODO Auto-generated method stub
StatusEventManager.getInstance().removeListener(this);
}
}
Receiver除了繼承Device外,還另外實作了StatusListener,在初始化時呼叫StatusEventManager註冊其為監聽者! 而在監聽到事件後會在updateStatus上做相對的行為
#事件分派者 (StatusEventManager)
public class StatusEventManager {
private List<StatusListener> listeners;
private static StatusEventManager instance;
private StatusEventManager() {
}
public static StatusEventManager getInstance() {
if(instance == null) {
instance = new StatusEventManager();
}
return instance;
}
public void addListener(StatusListener stateListener) {
if (listeners == null) {
listeners = new ArrayList<>();
}
System.out.println("Register "+stateListener+" listener to StatusEventManager");
listeners.add(stateListener);
}
public void removeListener(StatusListener stateListener) {
if (listeners == null)
return;
System.out.println("Remove "+stateListener+" listener from StatusEventManager");
listeners.remove(stateListener);
}
public void dispatchStatusUpdate(StatusEvent e) {
if(listeners != null) {
for(StatusListener stateListener : listeners) {
Object src = e.getSource();
if(src instanceof IDevice) {
IDevice dev = (IDevice) src;
System.out.println("### "+dev+" dispatch \""+dev.getStatus()+"\" status to "+stateListener+" by StatusEventManager");
stateListener.updateStatus(e);
}
}
}
}
}
StatusEventManager主要是分派事件給監聽者,只要是註冊在它下面的listener都可以收到事件的物件
#監聽者 (StatusListener)
定義監聽者要實作的行為
public interface StatusListener extends EventListener{
public void updateStatus(StatusEvent event);
}
定義監聽者要實作的行為
#事件物件 (StatusEvent.java)
public class StatusEvent extends EventObject{
public StatusEvent(Object source) {
super(source);
// TODO Auto-generated constructor stub
}
}
包裝事件是由哪個source所觸發的
#主程式 (Main.java)
前面的各支程式介紹過後,接下來示範如何操作
public class Main {
public static void main(String[] args) {
IDevice control = new Controller("Remote Controller");
IDevice receiver1 = new Receiver("Television");
IDevice receiver2 = new Receiver("Air conditioner");
System.out.println("======================================================");
showStatus(control, receiver1, receiver2);
control.open();
showStatus(control, receiver1, receiver2);
control.close();
showStatus(control, receiver1, receiver2);
receiver1.dispose();
receiver2.dispose();
}
public static void showStatus(IDevice ...device) {
System.out.println("[Query device status]");
for(IDevice d : device) {
System.out.println(d.getName() + " status is "+d.getStatus());
}
System.out.println();
}
}
首先建構出一遙控器(Controller)、兩個接收器(Receiver),Receiver在建構當下會呼叫StatusEventManager註冊這個listener。當遙控器呼叫open後,會觸發StatusEventManager去進行事件分派的動作,也就是將手上所註冊的listener,輪詢一遍呼叫listener實作的updateStatus。透過updateStatus傳入的event object,從中取得目前遙控器的狀態,藉此改變Receiver的狀態成RUNNING。最後當Receiver不須使用後,記得呼叫dispose將listener從StatusEventManager上移除掉
執行結果如下:
留言
張貼留言