先引入四人幫之書裏面關於觀察者模式的一段高度概括
觀察者模式——
定義對象間的一種一對多的依賴關係,當一個對象的狀態發生變化時,所有依賴它的對象都得到通知並自動更新。
事件驅動模型是觀察者模式的一種典型應用。該模式主要由事件源,事件對象,以及事件監聽器三元素構成。以常見的點擊事件爲例子。按鈕爲事件源,相當於觀察者模式中的被觀察者;點擊爲事件對象;事件監聽器,相當於觀察者模式中的觀察者。當事件源的屬性發生變化時,所有監聽該事件的事件監聽器都會接收到消息並作出響應。
關於“事件”這種抽象,最直觀的是在於圖形界面應用裏,如常見的點擊、拖動事件。實際上,世間萬物各種屬性的變化,我們都可以稱爲事件。例如風停了,怪物死亡了等等。
下面以具體代碼作例子,說明事件驅動模型的應用。
假設這樣的業務需求:遊戲服務器希望在玩家升級時觸發多種效果。例如玩家升級後,各種屬性都會提高,開啓新的系統玩法,學習新的技能……如果不採用事件驅動模型,那麼寫出來的代碼可能是這樣——
private void handleRoleUpgrade(Object role){
if(meetUpgradeCondition(role)){//滿足升級條件
RoleManager.getInstance().upgradeAttribution(role);//屬性提升
SkillManager.getInstance().learnNewSkill(role);//學會新技能
//其他一堆業務
}
}
所有相關業務的邏輯都耦合到這裏。當然,這樣做也有好處,最重要的一點是業務邏輯絕對清晰。
如果使用事件驅動模型,那麼在這裏只需分發一個升級事件,那麼該事件的所有監聽器便會自動作出響應。
首先定義事件類(Event.java)
事件類以玩家暱稱代表事件源,將事件源綁定在事件類,是爲了程序方便。
package observer;
public class Event {
private final String userName; //玩家暱稱
private final EventType evtType; //事件類型
public Event(String userName,EventType evtType){
this.userName = userName;
this.evtType = evtType;
}
public String getUserName() {
return userName;
}
public EventType getEvtType() {
return evtType;
}
}
事件類型枚舉(EventType.java)package observer;
public enum EventType {
LEVEL_UP, //角色升級
;
}
具體事件——升級事件(LevelUpEvent.java)
package observer;
public class LevelUpEvent extends Event{
public LevelUpEvent(String userName, EventType evtType) {
super(userName, evtType);
}
}
事件監聽器接口(EventListener.java)
package observer;
public interface EventListener {
public void handleEvent(Event event);
}
具體事件監聽器——屬性變化監聽器(AttrChangeListener.java)package observer;
/**
* 屬性變化監聽器
*/
public class AttrChangeListener implements EventListener{
@Override
public void handleEvent(Event event) {
System.err.println(event.getUserName()+"升級了,攻擊力,防禦力都將大幅提升");
}
}
具體事件監聽器——學習技能監聽器(SkillListener.java)
package observer;
public class SkillListener implements EventListener{
@Override
public void handleEvent(Event event) {
System.err.println(event.getUserName()+"升級了,學會劍神新技能");
}
}
事件分發器接口,主要用於事件的註冊及派發(EventDispatcher.java)package observer;
public interface EventDispatcher {
/**
* 註冊事件
*/
public void registerEvent(EventType evtType,EventListener listener);
/**
* 派發事件
*/
public void fireEvent(Event event);
}
具體事件分發器(CommonEventDispatcher.java)package observer;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
public enum CommonEventDispatcher implements EventDispatcher{
INSTANCE; //採用枚舉實現單例模式
private final Map<EventType,Set<EventListener>> observers = new HashMap<>();
@Override
public void registerEvent(EventType evtType, EventListener listener) {
Set<EventListener> listeners = observers.get(evtType);
if(listeners == null){
listeners = new CopyOnWriteArraySet<EventListener>();
observers.put(evtType, listeners);
}
listeners.add(listener);
}
@Override
public void fireEvent(Event event) {
if(event == null){
throw new NullPointerException("event cannot be null");
}
EventType evtType = event.getEvtType();
Set<EventListener> listeners = observers.get(evtType);
if(listeners != null){
for(EventListener listener:listeners){
try{
listener.handleEvent(event);
}catch(Exception e){
e.printStackTrace(); //防止其中一個listener報異常而中斷其他邏輯
}
}
}
}
}
測試代碼(Test.java)package observer;
public class Test {
public static void main(String[] args) {
CommonEventDispatcher dispatcher = CommonEventDispatcher.INSTANCE;
EventListener listener1 = new AttrChangeListener();
EventListener listener2 = new SkillListener();
Event levelUpEvent = new LevelUpEvent("李逍遙",EventType.LEVEL_UP);
dispatcher.registerEvent(EventType.LEVEL_UP, listener1);
dispatcher.registerEvent(EventType.LEVEL_UP, listener2);
dispatcher.fireEvent(levelUpEvent);
}
}
程序運行截圖