先引入四人帮之书里面关于观察者模式的一段高度概括
观察者模式——
定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都得到通知并自动更新。
事件驱动模型是观察者模式的一种典型应用。该模式主要由事件源,事件对象,以及事件监听器三元素构成。以常见的点击事件为例子。按钮为事件源,相当于观察者模式中的被观察者;点击为事件对象;事件监听器,相当于观察者模式中的观察者。当事件源的属性发生变化时,所有监听该事件的事件监听器都会接收到消息并作出响应。
关于“事件”这种抽象,最直观的是在于图形界面应用里,如常见的点击、拖动事件。实际上,世间万物各种属性的变化,我们都可以称为事件。例如风停了,怪物死亡了等等。
下面以具体代码作例子,说明事件驱动模型的应用。
假设这样的业务需求:游戏服务器希望在玩家升级时触发多种效果。例如玩家升级后,各种属性都会提高,开启新的系统玩法,学习新的技能……如果不采用事件驱动模型,那么写出来的代码可能是这样——
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); } }程序运行截图