天天看点

JAVA 实现 委托事件

遗留问题:当监听事件的方法 参数不一致时,会直接报错,而不是 不执行

如果没有其他问题,应该是最终版本了。如有发现问题的大神,请留言谢谢

/**
 * @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();

    }

}