Java中监听器的目的是什么?

18
我在网上查找了相关信息,但没有找到一个足够清晰明了的解释。我看到一个Java接口,将它作为"监听器"参数传递给另一个类。人们添加不同的监听器到列表中,并通过单个方法调用它们。
我不确定为什么要使用它。有人可以解释一下吗?
这是我的原始求助帖子,有人告诉我要使用监听器。链接

1
你能否请粘贴一段让你感到困惑的代码片段呢? Listeners 相对比较通用,所以在没有具体的代码示例的情况下很难进行解释。 - Sergey Kalinichenko
啊,当然没问题。我没有卡在某段具体的代码上。我只是在寻求帮助,有人建议使用代码片段。我现在会发布它。 - Jacob Macallan
1
你可能正在寻找观察者模式的解释(这是一个通用概念,不仅限于Java)。 - Pshemo
7个回答

23
在您提供的代码示例中,链接了 KillMonsterEventListener
public interface KillMonsterEventListener {
    void onKillMonster ();
}

提供了一种让您的API用户告诉您以下内容的方法:

这是一段代码。当怪物被杀死时,请回调它。我会决定该做什么。

这是让我在您的执行流中的特定点(具体来说,在怪物被杀死时)插入我的代码的一种方法。我可以像下面这样做:

yourClass.addKillMonsterEventListener(
    new KillMonsterEventListener() {
        public onKillMonster() {
            System.out.println("A good monster is a dead monster!");
        }
    }
);

我可以在别处添加另一个监听器:

yourClass.addKillMonsterEventListener(
    new KillMonsterEventListener() {
        public onKillMonster() {
            monsterCount--;
        }
    }
);

当您的代码遍历杀死怪物的监听器列表时,即

for (KillMonsterEventListener listener : listeners) {
    listener.onKillMonster()
}

我的两个代码片段(即monsterCount--和输出)都会执行。它的好处在于,您的代码完全与我的代码解耦,您的代码不知道我在打印什么,我在递减哪个变量等。


这正是我所需要的解释类型。我不知道它们也被称为观察者。 - Jacob Macallan
你在“for”语句中使用的listeners对象是如何定义的?它是一个ArrayList吗? - Tobia

20

监听器是Java中实现观察者 设计模式的一种常见形式。这种技术也被称为回调, 这个术语来自过程式语言的世界。

观察者通过可观察对象注册自己,可观察对象在某些事件发生或需要通知观察者时回调观察者。

许多框架库扮演了可观察对象的角色,例如:

  • 您可以将自己(即侦听器接口的实现)注册为消息中间件中传入消息的侦听器。
  • 您可以将自己注册为操作系统用户所做更改的侦听器。
  • 您可以将自己注册为GUI事件的侦听器,例如单击按钮。

Java代码示例:

第一部分 - 可观察实体

import java.util.LinkedList;
import java.util.List;

public class Observable {
    private List<Observer> observers;

    public Observable() {
        observers = new LinkedList<>();
    }

    public void addObsever(Observer observer) {
        observers.add(observer);
    }

    private  void notifyObservers(String whatHappened) {
        for (Observer observer : observers) {
            observer.onSomethingHappened(whatHappened);
        }
    }

    public void doSomeStuff() {
        // ...
        // Do some business logic here.
        // ...

        // Now we want to notify all the listeners about something.
        notifyObservers("We found it!");

        // ...
        // Do some business logic here
        // ...
    }
}

第二部分 - 观察者/监听器接口

public interface Observer {
    void onSomethingHappened(String whatHappened);
}

第三部分 - 观察者/监听器接口的基本实现
public class MyObserver implements Observer {
    @Override
    public void onSomethingHappened(String whatHappened) {
        System.out.println(whatHappened);
    }
}

第四部分 - 将所有内容结合在一起
public class Main {
    public static void main(String[] args) {

        // Create the observable.
        Observable myObservable = new Observable();

        // Create the observers (aka listeners).
        Observer myObserverA = new MyObserver();
        Observer myObserverB = new MyObserver();

        // Register the observers (aka listeners).
        myObservable.addObsever(myObserverA);
        myObservable.addObsever(myObserverB);

        myObservable.doSomeStuff();

    }
} 

标准输出的结果将会是:

We found it!
We found it!

6
这是编程范式之一,事件驱动编程。对象在某些场合下向其他对象发送消息,例如在它们改变时。这在 GUI 编程中经常使用。每个 GUI 小部件都由一个类实现。当您想要处理用户的鼠标单击等事件时,您可以将监听器(也称为事件处理程序)添加到 GUI 小部件中。当用户单击小部件时,小部件将事件发送给已注册的监听器,以便应用程序可以响应鼠标单击。这将框架(GUI 小部件类)和应用程序代码分离。(在某些 GUI 框架中,例如 Swing,您可以将任意数量的监听器添加到对象中;在其他情况下,您只能指定一个。)
此外,在其他领域中,事件驱动编程也非常有用。您可能希望观察对象(参见 观察者模式)。例如,支持此功能的集合如果其内容发生更改,可能会发送事件。如果需要在此发生时执行某些处理,则可以将自己添加为此类的监听器。否则,就需要在每次向集合添加项目时调用后处理,但这很容易出错。

1
Servlet监听器用于监听Web容器中的事件,例如创建会话、将属性放入会话或在另一个容器中进行暂停和激活等。要订阅这些事件,可以在web.xml中配置监听器,例如HttpSessionListener。
监听器会在实际物理请求中触发,并且可以附加到应用程序服务器中的事件。通过监听器,您可以跟踪应用程序级别、会话级别、生命周期更改、属性更改等。
您可以通过定义侦听器对象来监视和响应Servlet生命周期中的事件,当生命周期事件发生时,调用其方法。
以下是Servlet Listener的博客文章 http://array151.blogspot.in/2016/12/servlet-listener.html

0
使用监听器让其他代码通知您有关“条件”/“事件”的信息。例如,如果鼠标移动/点击/拖动,可以调用“鼠标监听器”。它取决于您的应用程序为什么提供监听器。

0

当事件发生时,监听器会执行一些工作。它们被称为“事件监听器”。 例如,我们在Java中有ActionListener接口。当事件发生时,它调用actionPerformed()方法。 您可以参考http://java.about.com/od/a/g/Actionlistener.htm获取更多信息。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接