爪哇岛。实现侦听器的正确模式1. 定义接口2. 创建侦听器 Setter3. 触发侦听器事件4. 在父级中实现侦听器回调

2022-09-01 13:59:49

通常情况下,我会遇到给定对象需要具有许多侦听器的情况。例如,我可能有

class Elephant {
  public void addListener( ElephantListener listener ) { ... }
}

但我会有很多这样的情况。也就是说,我还将有一个将具有 s 的对象。现在,s 和 s 是完全不同的:TigerTigerListenerTigerListenerElephantListener

interface TigerListener {
  void listenForGrowl( Growl qrowl );
  void listenForMeow( Meow meow );
}

interface ElephantListener {
  void listenForStomp( String location, double intensity );
}

我发现我总是要在每个动物类中不断重新实现广播机制,并且实现总是一样的。是否有首选模式?


答案 1

您可以发送的每个事件类型,而不是每个事件类型都有特定的方法,而是将接口更改为接受泛型类。然后,如果需要,可以将子类化为特定子类型,或者让它包含状态,例如 。ListenerEventEventdouble intensity

TigerListener和ElephentListener随后成为

interface TigerListener {
    void listen(Event event);
}

实际上,您可以进一步将此接口重构为一个普通的:Listener

interface Listener {
    void listen(Event event);
}

然后,您的实现可以包含它们所关注的特定事件所需的逻辑。Listener

class TigerListener implements Listener {
    @Overrides
    void listen(Event event) {
        if (event instanceof GrowlEvent) {
            //handle growl...
        }
        else if (event instance of MeowEvent) {
            //handle meow
        }
        //we don't care about any other types of Events
    }
}

class ElephentListener {
    @Overrides
    void listen(Event event) {
        if (event instanceof StompEvent) {
            StompEvent stomp = (StompEvent) event;
            if ("north".equals(stomp.getLocation()) && stomp.getDistance() > 10) { 
                ... 
            }
        }
    }
}

订阅者和发布者之间的关键关系是发布者可以将事件发送到订阅者,但不一定可以向其发送某些类型的事件 - 这种类型的重构将该逻辑从接口向下推送到特定的实现中。


答案 2

对于那些来到这里只是想成为一个倾听者的人来说,这是一个更一般的答案。我总结了从 CodePath 创建自定义侦听器。如果您需要更多解释,请阅读该文章。

以下是步骤。

1. 定义接口

这是在需要与某个未知父级进行通信的子类中。

public class MyClass {

    // interface
    public interface MyClassListener {
        // add whatever methods you need here
        public void onSomeEvent(String title);
    }
}

2. 创建侦听器 Setter

将私有侦听器成员变量和公共 setter 方法添加到子类。

public class MyClass {

    // add a private listener variable
    private MyClassListener mListener = null;

    // provide a way for another class to set the listener
    public void setMyClassListener(MyClassListener listener) {
        this.mListener = listener;
    }


    // interface from Step 1
    public interface MyClassListener {
        public void onSomeEvent(String title);
    }
}

3. 触发侦听器事件

子对象现在可以调用侦听器接口上的方法。请务必检查 null,因为可能没有人在侦听。(也就是说,父类可能没有为我们的侦听器调用 setter 方法。

public class MyClass {

    public void someMethod() {
        // ...

        // use the listener in your code to fire some event
        if (mListener != null) 
            mListener.onSomeEvent("hello");
    }


    // items from Steps 1 and 2

    private MyClassListener mListener = null;

    public void setMyClassListener(MyClassListener listener) {
        this.mListener = listener;
    }

    public interface MyClassListener {
        public void onSomeEvent(String myString);
    }
}

4. 在父级中实现侦听器回调

父级现在可以使用我们在子类中设置的侦听器。

示例 1

public class MyParentClass {

    private void someMethod() {

        MyClass object = new MyClass();
        object.setMyClassListener(new MyClass.MyClassListener() {
            @Override
            public void onSomeEvent(String myString) {
                // handle event
            }
        });
    }
}

示例 2

public class MyParentClass implements MyClass.MyClassListener {

    public MyParentClass() {
        MyClass object = new MyClass();
        object.setMyClassListener(this);
    }

    @Override
    public void onSomeEvent(String myString) {
        // handle event
    }
}

推荐