【问题标题】:Java: Getting object from bound-method-referenceJava:从绑定方法引用中获取对象
【发布时间】:2016-04-02 09:37:11
【问题描述】:

TL;DR

是否有某种方法可以从使用方法引用调用的函数 do_something 中获取 my_object

other_object.do_something(my_object::some_method);

全文...

背景:我正在制作一个系统,其中模块通过相互传递事件进行通信。每个模块通过<EventType> void eat_event(EventType ev) 形式的一个或多个方法使用事件。 (可能有不同的方式来吃事件,并且给定的模块可能能够使用不同的方法来吃不同类型的事件)。每个模块维护一个消费者列表,并向他们发送事件。模块通过 add_listener 方法连接:

class Module{
    ...
    public <EventType> void add_listener(Consumer<EventType> consumer){
        this.listeners.add(consumer);
    }
}

在初始化代码中,我将模块绑定在一起,如下所示:

module_1.add_listener(module_2::eat_event);

现在,问题: 是否有某种方法可以提取方法引用module_2::eat_event 所属的对象(在本例中为module_2)?假设,出于某种原因,我希望module_1 维护它向其发送事件的所有模块的表。目前,我必须将 add_listener 定义更改为:

public <EventType> void add_listener(Module dest_module, Consumer<EventType> consumer){...}

并绑定:

module_1.add_listener(module_2, module_2::eat_event);

当您将所有内容绑定在一起时,这看起来是多余的,并且为编程错误打开了空间,因为您可能不小心指定了不属于目标模块的方法。

真正的问题:我为了这个问题而简化了问题,但真正的问题是我正在构建一个中间“路由器”类,它可能想要缓冲 @ 的输出987654332@,然后将它们喂给module_2。问题是当我通过路由器类指定连接时,我需要知道模块之间的依赖结构,当你传入一个源模块和一个目标模块的方法引用时,它就会丢失。

目前的结论

(2015 年 12 月 29 日 15:30 更新) 不,据我所知,没有办法做到这一点。

而且,我发现我不需要为我的程序执行此操作...因此,尽管您可能出于某些原因想要执行此操作,但我的不是其中之一。

【问题讨论】:

  • 您如何获得要添加为 module_1 中的侦听器之一的 module_2::eat_event?
  • 将所有模块绑定在一起的类包含对所有模块的引用。所以它只是this.module_1.add_listener(this.module_2::eat_event);
  • 您已经引用了所有模块,并且您希望维护一个将事件发送到的所有模块的表,在这种情况下,每当您调用 add_listener 并且您知道那个 eat_event 的模块(我假设它是class ) 属于:添加到 hashmap:map_of_listeners.put(module,eat_event) - 这是在 add_listener 里面。我的意思是首先检查它是否在地图中,否则将其添加到地图中,然后在稍后获取所有侦听器时,只需遍历该地图的值。
  • 不,我要在示例中维护的不是“侦听器表”,而是“每个侦听器所属模块的表”。所以我想获取“eat_event”所属的对象。如果没有问题中提到的冗余代码,我不确定这是否可能。
  • 我假设您可以访问eat_event 类(如果我没记错的话),但您无权访问拥有eat_event 侦听器类的类。那就是问题所在。我知道使用 Java 反射你可能能够实现它,但我认为它有点矫枉过正。如果不指定 eat_event 属于哪个模块,我不确定是否可以这样做。

标签: java events observer-pattern method-reference


【解决方案1】:

当您定义具有Consumer&lt;EventType&gt; 类型参数的方法时,不能保证Consumer 的实现是方法引用,也不能保证,如果它是通过方法引用实现的,它已经捕获了一个对象特定类型的。如果你想声明两个参数之间的特定依赖关系,你可以反过来做:

public <M extends Module, E> void add_listener(M dest_module, BiConsumer<M,E> listener){
    ...
}

由于该方法预计会记住dest_modulelistener 之间的关联,因此将dest_module 作为accept 方法的第一个参数提供给listener 应该没有问题。

在这个星座中,监听器根本不需要捕获模块实例。源自您的示例的典型用例如下:

module_1.add_listener(module_2, TypeOfModule2::eat_event);

这里,方法引用不会捕获模块实例,监听器通知实现最终会在注册时提供的实例上调用eat_event 方法。所以这里没有冗余,也没有机会混淆模块实例。

但是,如前所述,不能保证add_listener 的调用者如何实现侦听器接口。你不能阻止所有可能的抵消实现。您只能尝试使有意的实现变得容易,而反作用的东西更难以实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-25
    • 2014-09-04
    • 2011-01-11
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多