当前位置: 首页 > 知识库问答 >
问题:

使用方法句柄对功能接口进行转发调用

单喜
2023-03-14

太长别读:我试图找到最有效的动态创建功能接口的实现,将调用转发到该接口的一组实例。

目标是简化接口的实现,通过将处理程序(实现为功能接口)传递给适当的注册函数,允许客户端代码为多个事件注册自己。例如:

/** The interface in question we want to implement with minimal effort. */
interface TrainStation {
    void onTranArrived(TrainArrivedHandler handler);

    void onPassengerArrived(PassengerArrivedHandler handler);

    interface TrainArrivedHandler {
        void apply(String track, String lineNumber);
    }

    interface PassengerArrivedHandler {
        void apply(String track);
    }
}

这可能是这种接口的一个示例。有许多这样的接口,每个接口都有不同的事件,因此实现应该尽可能简单,没有太多重复的代码。我想这最好是通过在这样的实现中引入一个内部使用的Event类型来实现,它允许将调用转发到所有注册的处理程序:

/** Used in an implementation to implement on*() functions. */
interface Event<HANDLER> {
    /** Register a handler. */
    void on(HANDLER handler);

    /** Returned instance calls all registered handlers. */
    HANDLER getMasterHandler();

    static <HANDLER> Event<HANDLER> create() {
        // Magic. May need an instance of Class<HANDLER>, which is okay.
    }
}

然后,TrainStation的实现可能如下所示:

final class TrainStationImpl implements TrainStation {
    private final Event<TrainArrivedHandler> trainArrivedEvent = Event.create();
    private final Event<PassengerArrivedHandler> passengerArrivedEvent = Event.create();

    @Override
    public void onTranArrived(TrainArrivedHandler handler) {
        trainArrivedEvent.on(handler);
    }

    @Override
    public void onPassengerArrived(PassengerArrivedHandler handler) {
        passengerArrivedEvent.on(handler);
    }

    /** Generates some events. */
    public void makeSomethingHappen() {
        trainArrivedEvent.getMasterHandler().apply("34", "S12");
        passengerArrivedEvent.getMasterHandler().apply("2"); // Wants to catch the S12, but is obviously too late now.
    }
}

这是一个可管理的所需代码级别。它的大部分可以提取到一个抽象类中,因此每个接口只需要一次。当然,任何减少它的方法都是一个优点,但我看不到不公开事件实例的简单方法。

随着这种方法的发展,有趣的事情是接口事件的实现。我当然可以想象用普通的旧反射来做这件事,这是可以接受的,但不是真正出色的性能。但是我认为Java1.7或1.8现在应该有一种更有效和/或更直接的方法来实现Event.getMasterHandler()的返回值,使用新的API,尤其是方法处理,因为我们知道每个处理程序接口都是一个功能接口。我该如何做到这一点?

共有1个答案

曾云
2023-03-14

虽然原则上,您可以使用方法句柄来构造委托给多个目标的组合句柄,但没有办法以功能接口的有效实现的形式提供它。

LambdaMetafactory 创建高效的实现,但目前仅支持直接方法句柄,因此您不能在此处使用组合句柄。MethodHandleProxies 支持任意句柄,但当前使用反射代理功能,您希望避免其开销。

最好的解决方案是接受每个接口需要一些显式代码,但使用 Java

interface TrainArrivedHandler {
    void apply(String track, String lineNumber);
    static TrainArrivedHandler forAll(Iterable<TrainArrivedHandler> all) {
        return (track, lineNumber) -> all.forEach(h -> h.apply(track, lineNumber));
    }
}
interface PassengerArrivedHandler {
    void apply(String track);
    static PassengerArrivedHandler forAll(Iterable<PassengerArrivedHandler> next) {
        return track -> next.forEach(h -> h.apply(track));
    }
}

final class TrainStationImpl implements TrainStation {

    private final Set<TrainArrivedHandler> trainArrivedHandler=new HashSet<>();
    private final Set<PassengerArrivedHandler> passengerArrivedHandler=new HashSet<>();

    public void onTranArrived(TrainArrivedHandler handler) {
        trainArrivedHandler.add(handler);
    }
    public void onPassengerArrived(PassengerArrivedHandler handler) {
        passengerArrivedHandler.add(handler);
    }

    /** Generates some events. */
    public void makeSomethingHappen() {
        TrainArrivedHandler.forAll(trainArrivedHandler).apply("34", "S12");
        // Wants to catch the S12, but is obviously too late now.
        PassengerArrivedHandler.forAll(passengerArrivedHandler).apply("2");
    }
}

请注意,保存侦听器的< code >集合的实际类型没有硬连线到< code >接口中,事实上,任何< code>Iterable都可以。因此,我在这里使用< code>Set作为示例,但是如果您愿意,您可以创建一个更复杂的专用于侦听器存储解决方案。它可以完全按照您的问题的意图通用,它只需实现< code>Iterable,而使用正确参数类型调用每个侦听器将由侦听器< code >接口处理

 类似资料:
  • 使用ByteBuddy,我可以通过调用另一个实例方法并转换结果来实现一个实例方法吗? 例如(玩具): 鉴于上述情况,我能否实现,以便它调用并返回返回字符串的长度?也就是说,好像它是: 我天真地尝试了以下方法: 然而,看起来我的想法是错误的,;它看起来像是在生成的实例上调用的。 我还试过一个拦截器: 与: 这运行了,但产生了毫无意义的结果,在中设置断点和/或添加打印语句表明它永远不会被调用;所以很明

  • 我试图捕获一个,其中包含XML规则中不允许使用的字符。(例如,” 我已经阅读了描述方法的Javadoc。但是,我没有看到它无法捕获ValidationEvent。 从指定的InputStream中解组XML数据并返回结果内容树。使用此形式的解组API时,验证事件位置信息可能不完整。 在最后一次尝试中,我尝试在网上搜索,但什么也找不到<任何帮助都将不胜感激:D 我很抱歉补充一个问题。(POJO类有点

  • 我正在测试一个包含多个webview/页面的webview应用程序。为了获得webviews,我做了以下工作: 它返回一个窗口索引数组,这些索引数组类似于

  • 我正在开发一个具有蓝牙功能的应用程序。我使用一个片段来扫描并列出蓝牙设备。单击时,会回调到提供所选蓝牙设备的主要活动。 我一开始使用的是Android 6(API 23)的智能手机,然后不得不调整代码以适应Android 5.0(API 21)的使用。 我只是将minSDK更改为API21并重新构建了项目,没有任何问题。 该应用程序在智能手机上运行时没有任何问题。安装了Android5的平板电脑运

  • 我是Android的新手,我正在开发一个应用程序,该应用程序试图连接服务器并获取Json响应,将其解析为类并使其可用。 为此,我上了三门课 公共类顾客{} 公共类ServerConnect{} 公共类JsonParser{} Serverconnect使用Volley库在异步线程上下载网页源代码。下载后,Server Connect类启动OnServerResponsed(String Respo

  • 本文向大家介绍python使用suds调用webservice接口的方法,包括了python使用suds调用webservice接口的方法的使用技巧和注意事项,需要的朋友参考一下 最近做接口对接,遇到了.net开发的webservice接口,因为python第一次与webservice对接,连问带查,最后使用suds库来实现了 1.安装suds   mac: sudo pip install su