如何将事件通知返回到 Java 控制台应用程序的主程序 class?

How do you get event notifications back to the main program class of a Java console app?

我是从 C# 转到 Java,我真的只是想弄清楚如何在 Java 世界中做事。我在 IntelliJ IDEA 中 运行 Java 8。我发现 this 将 Java 中的事件解释为基本上是通过手动注册和接口方法调用手工制作的。代码示例有很多问题,我认为它从未被编译过。稍微清理一下后,我得到了这个:

接口节拍器事件:

public interface MetronomeEvent {
    void Tick(Date tickDate);
}

Class EventFiringSource:

public class EventFiringSource {

    // Our collection of classes that are subscribed as listeners of our
    protected List<MetronomeEvent> _listeners=new ArrayList();

    // Method for listener classes to register themselves
    public void addMetronomeEventListener(MetronomeEvent listener)
    {
        _listeners.add(listener);
    }

    // "fires" the event
    protected void fireMetronomeEvent()
    {
        if (_listeners != null && !_listeners.isEmpty())
        {
            for (MetronomeEvent e:_listeners)
            {
                e.Tick(new Date());
            }
        }
    }

    public void Start()
    {
        fireMetronomeEvent();
    }
}

主控制台应用程序:

public class MainApp implements MetronomeEvent {

    public static void main(String[] args) {
        EventFiringSource source = new EventFiringSource();
        source.addMetronomeEventListener(this); // Adds itself as a listener for the event
        source.Start();
    }

    public void Tick(Date tickDate)
    {
        System.out.println(tickDate.toString());
    }
}

剩下的一个错误是 source.addMetronomeEventListener(this);,其中编译器抱怨它无法从静态上下文中引用 MyApp.this。这是有道理的,但我看不出有什么办法可以在主程序 class 上实现 MetronomeEvent 接口后,实际将其传递给 source.addMetronomeEventListener() 进行注册。难道不能直接在主程序class上注册事件吗?我是否应该创建并注册一个监听器 class 来实现 MetronomeEvent 并将代表主应用程序执行操作?像这样?

public class Listener implements MetronomeEvent {
    public void Tick(Date tickDate){
        System.out.println(tickDate.toString());
    }
}

然后:

public static void main(String[] args) {
    EventFiringSource source = new EventFiringSource();
    Listener l=new Listener();
    source.addMetronomeEventListener(l); // Adds another object to listen on behalf of main()
    source.Start();
}

基于 Vince Emigh 的 comment/answer 我被引导 to this Oracle doc on lamda expressions and to this one on method references。到目前为止,我已经找到了 3 种方法。

1) 匿名 class:

    source.addMetronomeEventListener(
            new MetronomeEvent() {
                @Override
                public void Tick(Date tickDate) {
                    System.out.println("anonymous class:");
                    System.out.println(tickDate.toString());

                }
            }
    ); // Adds itself as a listener for the event 

2) Lambda 表达式:

source.addMetronomeEventListener(d -> System.out.println("lambda:\n"+d.toString()));

3) 方法参考,最接近我习惯的。 main中定义了一个方法class:

public static void processTick(Date tickDate){
    System.out.println("method reference:");
    System.out.println(tickDate.toString());
}

...然后在 main() 的主体中将其添加为事件处理程序,如下所示:

source.addMetronomeEventListener(MainApp::processTick);

这与事件无关,它与 main() 和一般的静态方法有关。

我建议将 main() 写成

public static void main(String[] args) {
    new MainApp(args).execute();
}

这样您就可以立即从静态函数世界跳转到面向对象的世界。