为什么需要使用事件模式
先来看一个业务场景:
产品经理:这两天你帮我实现一个注册的功能
我:注册功能比较简单,将用户信息入库就可以了,伪代码如下:
public void registerUser(UserModel user){
//插入用户信息到db,完成注册
this.insertUser(user);
}
过了几天,产品经理:注册成功之后,给用户发送一封注册成功的邮件
我:修改了一下上面注册代码,如下:
public void registerUser(UserModel user){
//插入用户信息到db,完成注册
this.insertUser(user);
//发送邮件
this.sendEmailToUser(user);
}
又过了几天,产品经理:注册成功之后,给用户发一下优惠券
public void registerUser(UserModel user){
//插入用户信息到db,完成注册
this.insertUser(user);
//发送邮件
this.sendEmailToUser(user);
//发送优惠券
this.sendCouponToUser(user);
}
过了一段时间,公司效益太好,产品经理:注册的时候,取消给用户发送优惠券的功能。
又过了几天,产品经理又跑来了说:路人,最近效益不好,需要刺激用户消费,注册的时候继续发送优惠券。
反反复复业务迭代。让测试也反反复复来回搞。会使我们的注册接口更加的复杂。有可能影响到主要功能的性能。
其实上面代码可以这么做:
找3个人:注册器、路人A、路人B。
注册器:负责将用户信息落库,落库成功之后,喊一声:用户XXX注册成功了。
路人A和路人B,竖起耳朵,当听到有人喊:XXX注册成功 的声音之后,立即行动做出下面反应:
路人A:负责给XXX发送一封注册邮件
路人B:负责给XXX发送优惠券
我们来看一下:
注册器只负责将用户信息落库,及广播一条用户注册成功的消息。
A和B相当于一个监听者,只负责监听用户注册成功的消息,当听到有这个消息产生的时候,A和B就去做自己的事情。
这里面注册器是感知不到A/B存在的,A和B也不用感知注册器的存在,A/B只用关注是否有人广播:XXX注册成功了的消息,当AB听到有人广播注册成功的消息,他们才做出反应,其他时间闲着休息。
这种方式就非常好:
当不想给用户发送优惠券的时候,只需要将B去掉就行了,此时基本上也不用测试,注册一下B的代码就行了。
若注册成功之后需要更多业务,比如还需要给用户增加积分,只需新增一个监听者C,监听到注册成功消息后,负责给用户添加积分,此时根本不用去调整注册的代码,开发者和测试人员只需要确保监听者C中的正确性就可以了。
上面这种模式就是事件模式。
事件模式中的几个概念
-
事件源:事件的触发者,比如上面的注册器就是事件源。
-
事件:描述发生了什么事情的对象,比如上面的:xxx注册成功的事件
-
事件监听器:监听到事件发生的时候,做一些处理,比如上面的:路人A、路人B
下面我们使用事件模式实现用户注册的业务
我们先来定义和事件相关的几个类。
事件对象
/**
* 事件对象
*/
public abstract class AbstractEvent {
//事件源
protected Object source;
public AbstractEvent(Object source) {
this.source = source;
}
public Object getSource() {
return source;
}
public void setSource(Object source) {
this.source = source;
}
}
事件监听器
我们使用一个接口来表示事件监听器,是个泛型接口,后面的类型E表示当前监听器需要监听的事件类型,此接口中只有一个方法,用来实现处理事件的业务;其定义的监听器需要实现这个接口。
/**
* 事件监听器
*
* @param <E> 当前监听器感兴趣的事件类型
*/
public interface EventListener<E extends AbstractEvent> {
/**
* 此方法负责处理事件
*
* @param event 要响应的事件对象
*/
void onEvent(E event);
}
事件广播器
负责事件监听器的管理(注册监听器&移除监听器,将事件和监听器关联起来)
负责事件的广播(将事件广播给所有的监听器,对该事件感兴趣的监听器会处理该事件)
/**
* 事件广播器:
* 1.负责事件监听器的管理(注册监听器&移除监听器,将事件和监听器关联起来)
* 2.负责事件的广播(将事件广播给所有的监听器,对该事件感兴趣的监听器会处理该事件)
*/
public interface EventMulticaster {
/**
* 广播事件给所有的监听器,对该事件感兴趣的监听器会处理该事件
*
* @param event
*/
void multicastEvent(AbstractEvent event);
/**
* 添加一个事件监听器(监听器中包含了监听器中能够处理的事件)
*
* @param listener 需要添加监听器
*/
void addEventListener(EventListener<?> listener);
/**
* 将事件监听器移除
*
* @param listener 需要移除的监听器
*/
void removeEventListener(EventListener<?> listener);
}
事件广播默认实现
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 事件广播器简单实现
*/
public class SimpleEventMulticaster implements EventMulticaster {
private Map<Class<?>, List<EventListener>> eventObjectEventListenerMap = new ConcurrentHashMap<>();
@Override
public void multicastEvent(AbstractEvent event) {
List<EventListener> eventListeners = this.eventObjectEventListenerMap.get(event.getClass());
if (eventListeners != null) {
for (EventListener eventListener : eventListeners) {
eventListener.onEvent(event);
}
}
}
@Override
public void addEventListener(EventListener<?> listener) {
Class<?> eventType = this.getEventType(listener);
List<EventListener> eventListeners = this.eventObjectEventListenerMap.get(eventType);
if (eventListeners == null) {