遗留问题:当监听事件的方法 参数不一致时,会直接报错,而不是 不执行
如果没有其他问题,应该是最终版本了。如有发现问题的大神,请留言谢谢
/**
* @Author 乔占江 qq:59663479
* @Data 2021/1/24 12:14
* @Description 如果想 发布事件 委托,需要实现这接口
* @Version 1.0
*/
public interface IEvent {
/**
* 使用 Event时,实现这个接口,调用Event.init(this);Event会回调 iWantUseEvent 方法
*/
void iWantUseEvent();
/**
* 当 使用Event的对象 被销毁前,应该通知Event,把自己发布的 事件删除
* 这个接口 可以忽视,仅仅是告知作用;
*/
default void iNotUseEvent() {
Event.delete(this);
}
}
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author 乔占江 qq:59663479
* @Data 2021/1/23 20:37
* @Description 事件委托 实现
* @Version 3.0
*/
public class Event {
// 管理所有的 事件委托;
// Map<发布 事件委托 的对象,Map<事件委托 的名字,监听者 信息>>
private static Map<Object, Map<String, EventDefine>> events = new ConcurrentHashMap<>();
public static void init(IEvent user) {
// 回调 使用者
user.iWantUseEvent();
}
/**
* 发布一个 事件委托
*
* @param promulgator 发布 事件委托 的对象
* @param eventName 事件委托 名
*/
public static void release(Object promulgator, String eventName) {
Map<String, EventDefine> promulgatorEvent = events.get(promulgator);
// 没有这个对象的 事件委托,把这个对象 和本次发布的 事件委托 加入到 Map中
if (promulgatorEvent == null) {
promulgatorEvent = new ConcurrentHashMap<>();
promulgatorEvent.put(eventName, new EventDefine(eventName));
events.put(promulgator, promulgatorEvent);
// System.out.println(promulgator + " 发布了一个event,eventName为 " + eventName);
} else {
// 查看 是否已发布 过当前 事件委托,没发布过,则加入,发布过 则跳过
EventDefine eventDefine = promulgatorEvent.get(eventName);
if (eventDefine == null) {
promulgatorEvent.put(eventName, new EventDefine(eventName));
// System.out.println(promulgator + " 发布了一个event,eventName为 " + eventName);
} else {
System.out.println(promulgator + " 已发布过 eventName为 " + eventName + " 的 事件委托");
}
}
}
/**
* 监听 某个 事件
*
* @param promulgator 发布这个 事件委托 的对象
* @param receiver 监听者
* @param eventName 监听的 事件委托 名
* @param methodName 当事件触发,通知的方法
* @return
*/
public static boolean listen(Object promulgator, Object receiver, String eventName, String methodName) {
Map<String, EventDefine> promulgatorDefineMap = events.get(promulgator);
if (promulgatorDefineMap == null) {
System.out.println("没有 " + promulgator + " 发布的 事件委托");
return false;
}
// 获取这个对象发布的所有 事件委托
EventDefine eventDefine = promulgatorDefineMap.get(eventName);
if (eventDefine == null) {
System.out.println(promulgator + " 没有发布eventName为 " + eventName + " 的事件委托");
return false;
}
// 记录 事件委托 信息
eventDefine.add(receiver, methodName);
return true;
}
/**
* 不再监听 一个 事件委托
*
* @param promulgator 事件委托 发布者
* @param receiver 监听者
* @param eventName 事件委托 名字
*/
public static void remove(Object promulgator, Object receiver, String eventName) {
Map<String, EventDefine> promulgatorDefineMap = events.get(promulgator);
if (promulgatorDefineMap == null) {
System.out.println(promulgator + " 没有发布过 事件委托 ");
return;
}
// 获取这个对象发布的所有 事件委托
EventDefine eventDefine = promulgatorDefineMap.get(eventName);
if (eventDefine == null) {
System.out.println(promulgator + " 没有发布eventName为 " + eventName + " 的 事件委托");
return;
}
eventDefine.remove(receiver);
}
/**
* 不再发布 关于 eventName 的信息,将会删除这个 事件委托,以及所有 监听者信息
*
* @param promulgator 事件发布者
* @param eventName 不再发布的事件的名字
*/
public static void delete(Object promulgator, String eventName) {
Map<String, EventDefine> promulgatorDefineMap = events.get(promulgator);
if (promulgatorDefineMap != null) {
promulgatorDefineMap.remove(eventName);
System.err.println(promulgator + "不再发布eventName为 " + eventName + " 的事件");
}
}
/**
* 不再发布任何 事件委托
*
* @param promulgator 发布人
*/
public static void delete(Object promulgator) {
if (events.containsKey(promulgator)) {
events.remove(promulgator);
System.out.println(promulgator + " 将之前发布的事件全部移除了");
System.out.println("还发布有 事件委托 的对象个数为:" + events.size());
}
}
/**
* 触发一个 事件
*
* @param promulgator 这个事件是谁 发布的
* @param eventName 事件名
* @param params 传递的参数
*/
public static void invoke(Object promulgator, String eventName, Object... params) {
Map<String, EventDefine> promulgatorDefineMap = events.get(promulgator);
if (promulgatorDefineMap == null) {
System.out.println(promulgator + " 没有发布过 事件委托");
return;
}
EventDefine eventDefine = promulgatorDefineMap.get(eventName);
if (eventDefine == null) {
System.out.println(promulgator + " 没有发布eventName为 " + eventName + " 的 事件委托");
return;
}
eventDefine.send(params);
}
/**
* 当一个 事件委托 发布后,这个 事件委托 名字,对应一个 EventDefine
* EventDefine 中 包含所有 监听这个 事件委托 的 对象和方法名
*/
private static class EventDefine {
// 事件委托 名
private String eventName;
// Map<监听 事件委托 的对象,监听 事件委托 的方法名>
private Map<Object, String> eventMap = null;
public EventDefine(String eventName) {
this.eventName = eventName;
}
public void add(Object object, String methodName) {
if (eventMap == null) {
eventMap = new ConcurrentHashMap<>();
eventMap.put(object, methodName);
} else if (!eventMap.containsKey(object)) {
eventMap.put(object, methodName);
}
}
public void remove(Object object) {
eventMap.remove(object);
}
/**
* 通知所有 监听者
*
* @param params
*/
public void send(Object... params) {
// 根据要发送的数据,获取对应的 类型,然后使用反射获取 对应的方法;
Class[] classes = paramsToTypes(params);
try {
for (Object object : eventMap.keySet()) {
// 遇到问题:当参数不匹配时,直接抛出了异常;
// 期望是,参数不匹配返回null,是否有解决方案呢?
Method method = object.getClass().getMethod(eventMap.get(object), classes);
if (method != null) {
method.invoke(object, params);
} else {
System.out.println("没这方法");
}
}
} catch (Exception e) {
System.out.println("eventName为:" + eventName + "的调用发生了错误");
e.printStackTrace();
}
}
/**
* 将参数[] 转为 类型[] 返回
*/
private static Class[] paramsToTypes(Object... params) {
if (params == null) {
return null;
}
Class[] paramTypes = new Class[params.length];
for (int i = 0; i < params.length; i++) {
paramTypes[i] = params[i].getClass();
}
return paramTypes;
}
}
}
下面是配合 测试使用的代码
import com.card.event.Event;
import com.card.event.IEvent;
/**
* @Author 乔占江 qq:59663479
* @Data 2021/1/24 10:29
* @Description
* @Version 1.0
*/
public class Player implements IEvent {
private int hp;
private int mp;
private int gold;
Bag bag = new Bag();
@Override
public void iWantUseEvent() {
Event.release(this, "goldUpdate");
Event.release(this, "hpUpdate");
Event.release(this, "mpUpdate");
}
public Player() {
Event.init(this);
bag.init(this);
}
@Override
public void iNotUseEvent(){
Event.delete(this);
}
/**
* @param listener
* @param eventName
* @param methodName
*/
public void listenEvent(Object listener, String eventName, String methodName) {
Event.listen(this, listener, eventName, methodName);
}
public int getHp() {
return hp;
}
public void setHp(Integer hp) {
this.hp = hp;
Event.invoke(this, "hpUpdate", hp);
}
public int getMp() {
return mp;
}
public void setMp(Integer mp) {
this.mp = mp;
Event.invoke(this, "mpUpdate", mp);
}
public int getGold() {
return gold;
}
public void setGold(Integer gold) {
this.gold = gold;
Event.invoke(this, "goldUpdate", gold);
}
}
/**
* @Author 乔占江 qq:59663479
* @Data 2021/1/24 10:33
* @Description
* @Version 1.0
*/
public class Bag {
private Player owner;
public void init(Player player){
owner = player;
owner.listenEvent(this,"goldUpdate","onGoldUpdate");
owner.listenEvent(this,"hpUpdate","onHpUpdate");
owner.listenEvent(this,"mpUpdate","onMpUpdate");
}
/**
* 当金币发生改变时,会调用这个方法,这里本来可以不带参数,可以直接用 owner 获取
* 为了做测试 特意加了参数;这个参数必须是 对象类型。不可用是基本数据类型
*/
public void onGoldUpdate(Integer gold){
System.out.println("收到gold变化为:" + gold);
}
public void onHpUpdate(Integer hp){
System.out.println("收到hp变化为:" + hp);
}
public void onMpUpdate(Integer mp){
System.out.println("收到mp变化为:" + mp);
}
}
测试
public class EventDemo {
public static void main(String[] args) throws InterruptedException {
Player player = new Player();
player.setGold(1000);
player.setHp(800);
player.setMp(600);
player.iNotUseEvent();
}
}