先引入四人帮之书里面关于观察者模式的一段高度概括
一、观察者模式概念
定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都得到通知并自动更新。
事件驱动模型是观察者模式的一种典型应用。该模式主要由事件源,事件对象,以及事件监听器三元素构成。以常见的点击事件为例子。按钮为事件源,相当于观察者模式中的被观察者;点击为事件对象;事件监听器,相当于观察者模式中的观察者。当事件源的属性发生变化时,所有监听该事件的事件监听器都会接收到消息并作出响应。
关于“事件”这种抽象,最直观的是在于图形界面应用里,如常见的点击、拖动事件。实际上,世间万物各种属性的变化,我们都可以称为事件。例如风停了,怪物死亡了等等。
二、问题提出
假设这样的业务需求:游戏服务器希望在玩家升级时触发多种效果。例如玩家升级后,各种属性都会提高,开启新的系统玩法,学习新的技能……如果不采用事件驱动模型,那么写出来的代码可能是这样——
private void handleRoleUpgrade(Object role){
if(meetUpgradeCondition(role)){//满足升级条件
RoleManager.getInstance().upgradeAttribution(role);//属性提升
SkillManager.getInstance().learnNewSkill(role);//学会新技能
//其他一堆业务
}
}
所有相关业务的逻辑都耦合到这里。当然,这样做也有好处,最重要的一点是业务逻辑绝对清晰。
三、事件驱动实现
如果使用事件驱动模型,那么在这里只需分发一个升级事件,那么该事件的所有监听器便会自动作出响应。
3.1定义事件类
事件类以玩家昵称代表事件源,将事件源绑定在事件类,是为了程序方便。
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;
}
}
3.2事件类型枚举
public enum EventType {
LEVEL_UP, //角色升级
;
}
3.3具体事件——升级事件
public class LevelUpEvent extends Event{
public LevelUpEvent(String userName, EventType evtType) {
super(userName, evtType);
}
}
3.4事件监听器接口
public interface EventListener {
public void handleEvent(Event event);
}
3.5具体事件监听器——属性变化监听器
/**
* 属性变化监听器
*/
public class AttrChangeListener implements EventListener{
@Override
public void handleEvent(Event event) {
System.err.println(event.getUserName()+"升级了,攻击力,防御力都将大幅提升");
}
}
3.6具体事件监听器——学习技能监听器
public class SkillListener implements EventListener{
@Override
public void handleEvent(Event event) {
System.err.println(event.getUserName()+"升级了,学会剑神新技能");
}
}
3.7事件分发器接口,主要用于事件的注册及派发
public interface EventDispatcher {
/**
* 注册事件
*/
public void registerEvent(EventType evtType,EventListener listener);
/**
* 派发事件
*/
public void fireEvent(Event event);
}
3.8具体事件分发器
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报异常而中断其他逻辑
}
}
}
}
}
3.9测试代码
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);
}
}