如何使用Java实现回调监听工具类,实现高效事件通知

后端 潘老师 3周前 (04-17) 9 ℃ (0) 扫码查看

今天咱们就来聊聊如何用Java实现一个回调监听工具类,借助函数式接口Consumer,可以巧妙地解耦回调方法,这样开发出来的代码结构更清晰、更易于维护。下面,我们一步步来深入了解。

一、定义监听接口类Listenable

首先,我们要创建一个抽象的监听接口Listenable。这个接口的作用是提供一套通用的方法,用于管理和操作监听者。代码如下:

import java.util.*;
import java.util.function.Consumer;

public interface Listenable<Listener> {

    // 使用WeakHashMap来存储监听者,避免内存泄漏,键为当前对象,值为对应监听者的集合
    WeakHashMap<Object, Set> LISTENERS_WEAK_MAP = new WeakHashMap<>();

    // 注册监听者的方法
    default void registerListener(Listener listener) {
        // 检查传入的监听者是否为空,若为空则抛出异常
        Objects.requireNonNull(listener);
        Set<Listener> listeners;
        // 同步访问LISTENERS_WEAK_MAP,确保线程安全
        synchronized (LISTENERS_WEAK_MAP) {
            // 获取当前对象对应的监听者集合
            listeners = LISTENERS_WEAK_MAP.get(this);
            // 如果集合为空,则创建一个新的HashSet
            if (listeners == null) {
                listeners = new HashSet<>();
                // 将新创建的集合存入LISTENERS_WEAK_MAP中
                LISTENERS_WEAK_MAP.put(this, listeners);
            }
        }
        // 同步访问监听者集合,确保线程安全地添加监听者
        synchronized (listeners) {
            listeners.add(listener);
        }
    }

    // 注销监听者的方法
    default void unregisterListener(Listener listener) {
        // 检查传入的监听者是否为空,若为空则抛出异常
        Objects.requireNonNull(listener);
        Set<Listener> listeners;
        // 同步访问LISTENERS_WEAK_MAP,确保线程安全
        synchronized (LISTENERS_WEAK_MAP) {
            // 获取当前对象对应的监听者集合
            listeners = LISTENERS_WEAK_MAP.get(this);
            // 如果集合为空,直接返回,无需进行后续操作
            if (listeners == null) {
                return;
            }
        }
        // 同步访问监听者集合,确保线程安全地移除监听者
        synchronized (listeners) {
            listeners.remove(listener);
        }
    }

    // 获取所有监听者的方法
    default Collection<Listener> getListeners() {
        // 同步访问LISTENERS_WEAK_MAP,确保线程安全
        synchronized (LISTENERS_WEAK_MAP) {
            // 获取当前对象对应的监听者集合
            Set<Listener> listeners = LISTENERS_WEAK_MAP.get(this);
            // 如果集合为空,返回一个空的HashSet
            if (listeners == null) {
                return new HashSet<>();
            }
            // 返回一个包含所有监听者的新HashSet,避免直接返回原集合导致外部修改
            return new HashSet<>(listeners);
        }
    }

    // 检查某个监听者是否已注册的方法
    default boolean isListenerRegistered(Listener listener) {
        // 同步访问LISTENERS_WEAK_MAP,确保线程安全
        synchronized (LISTENERS_WEAK_MAP) {
            // 获取当前对象对应的监听者集合
            Set<Listener> listeners = LISTENERS_WEAK_MAP.get(this);
            // 如果集合为空,说明监听者未注册,返回false
            if (listeners == null) {
                return false;
            }
            // 检查集合中是否包含指定的监听者
            return listeners.contains(listener);
        }
    }

    // 遍历所有监听者并执行指定操作的方法,默认忽略异常
    default void forEachListener(Consumer<Listener> action) {
        forEachListener(action, true);
    }

    // 遍历所有监听者并执行指定操作的方法,可选择是否忽略异常
    default void forEachListener(Consumer<Listener> action, boolean ignoreException) {
        // 检查传入的操作是否为空,若为空则抛出异常
        Objects.requireNonNull(action);
        Iterable<Listener> listeners;
        // 同步访问LISTENERS_WEAK_MAP,确保线程安全
        synchronized (LISTENERS_WEAK_MAP) {
            // 获取当前对象对应的监听者集合
            Set<Listener> values = LISTENERS_WEAK_MAP.get(this);
            // 如果集合为空,直接返回,无需进行后续操作
            if (values == null) {
                return;
            }
            // 将监听者集合转换为ArrayList,以便进行遍历
            listeners = new ArrayList<>(values);
        }
        // 遍历监听者列表,对每个监听者执行指定操作
        for (Listener listener : listeners) {
            try {
                action.accept(listener);
            } catch (Exception e) {
                // 如果不忽略异常,则抛出捕获到的异常
                if (!ignoreException) {
                    throw e;
                }
            }
        }
    }
}

这个接口定义了一系列方法,包括注册监听者、注销监听者、获取所有监听者、检查监听者是否注册,以及遍历所有监听者并执行指定操作等。通过这些方法,我们可以方便地管理和操作监听者。

二、实际用法示例

了解了监听接口类的定义后,我们来看一下它在实际中的用法。下面以MessageManager类为例,展示如何使用这个监听接口来实现自定义的回调功能。

public class Main {

    // 定义MessageManager类,实现Listenable接口,监听类型为OnEventListener
    public static class MessageManager implements Listenable<MessageManager.OnEventListener> {

        // 私有化构造函数,确保单例模式
        private MessageManager() {}

        // 定义单例实例
        private static final MessageManager instance = new MessageManager();

        // 获取单例实例的方法
        public static MessageManager getInstance() {
            return instance;
        }

        // 当操作成功时,通知所有监听者的方法
        public void onSuccess(String json) {
            // 遍历所有监听者,并调用它们的onSuccess方法
            forEachListener(it->it.onSuccess(json));
        }

        // 当操作出错时,通知所有监听者的方法
        public void onError(int code, String error) {
            // 遍历所有监听者,并调用它们的onError方法
            forEachListener(it->it.onError(code, error));
        }

        // 定义监听者接口,包含操作成功和操作出错的回调方法
        public interface OnEventListener {
            void onSuccess(String json);
            void onError(int code, String error);
        }
    }

    public static void main(String[] args) {
        // 注册一个监听者
        MessageManager.getInstance().registerListener(new MessageManager.OnEventListener() {
            @Override
            public void onSuccess(String json) {
                // 操作成功时的回调处理
                System.out.println("onSuccess " + json);
            }

            @Override
            public void onError(int code, String error) {
                // 操作出错时的回调处理
                System.out.println("onError code:" + code + " error:" + error);
            }
        });

        // 模拟操作成功,调用onSuccess方法通知监听者
        MessageManager.getInstance().onSuccess("My json");
        // 模拟操作出错,调用onError方法通知监听者
        MessageManager.getInstance().onError(-1, "Error");
    }
}

在这个示例中,MessageManager类实现了Listenable接口,并定义了自己的监听者接口OnEventListener,包含onSuccessonError两个回调方法。在main方法中,我们注册了一个监听者,并分别调用onSuccessonError方法,模拟操作成功和出错的情况,观察监听者的回调处理。运行代码后,控制台会输出以下结果:

onSuccess My json
onError code:-1 error:Error

这表明我们成功实现了回调监听功能,当MessageManager中的操作状态发生变化时,注册的监听者能够及时收到通知并执行相应的处理逻辑。

通过上述步骤,我们成功实现了一个Java回调监听工具类,并展示了它的实际用法。这种方式可以帮助我们在开发过程中,更好地实现对象间的事件通信,提高代码的灵活性和可维护性。希望大家通过这篇文章,对Java的回调监听机制有更深入的理解和掌握。


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/back/17538.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】