Java - A Self-defined EventObject and EventListener example

對於事件的概念我想第一次的接觸莫過於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)

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)

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上移除掉

執行結果如下:

留言