什么是在具有不同参数的事件通知的最佳模式?

huangapple go评论139阅读模式
英文:

What is the best pattern for event notification with different arguments?

问题

以下是翻译好的内容:

我正在寻找以下内容的替代方案(方法1):

public interface IEventListener {
    void onFoo(String string, Integer integer, ObjectB objectB);
    void onBar(Double d, ObjectA objectA);
}

我在考虑类似于这样的方案(方法2):

public interface IEventListener {
    void onEvent(Event event);
}

public enum EVENT_TYPE {
    FOO, BAR
}

public abstract class Event {
    EVENT_TYPE type;
    abstract EVENT_TYPE getType();
}

public class FooEvent extends Event {
    private String string;
    private Integer integer;
    private ObjectB objectB;

    @Override
    EVENT_TYPE getType() {
        return EVENT_TYPE.FOO;
    }
}

public class BarEvent extends Event {
    private Double d;
    private ObjectA objectA;

    @Override
    EVENT_TYPE getType() {
        return EVENT_TYPE.BAR;
    }
}

但我不确定它是否易于使用。
为了处理事件,我需要检查事件类型并将事件转换为正确的类型,等等。

也许没有方法1的替代方案?

英文:

I'm looking for an alternative pattern to the following (method 1):

public interface IEventListener {
    void onFoo(String string, Integer integer, ObjectB objectB);
    void onBar(Double d, ObjectA objectA);
}

I'm thinking something like this (method 2):

public interface IEventListener {
    void onEvent(Event event);
}

public enum EVENT_TYPE {
    FOO, BAR
}

public abstract class Event {
    EVENT_TYPE type;
    abstract EVENT_TYPE getType();
}

public class FooEvent extends Event {
    private String string;
    private Integer integer;
    private ObjectB objectB;

    @Override
    EVENT_TYPE getType() {
        return EVENT_TYPE.FOO;
    }
}

public class BarEvent extends Event {
    private Double d;
    private ObjectA objectA;

    @Override
    EVENT_TYPE getType() {
        return EVENT_TYPE.BAR;
    }
}

But I'm not sure how it is easy to use.
To handle the event I need to check the event type and cast the event to the correct one, etc.

Maybe there is no alternative to method 1?

答案1

得分: 2

避免与常见祖先产生关联,除非你有明确的理由处理抽象事件(例如一些日志记录、计时、排队、序列化等)。

将监听器编码为lambda表达式也要简单得多。实际上,你最好考虑监听器类别,比如Consumer<Foo>和Consumer<Bar>。

事件提供者会实现类似于
addFooListener(Consumer<Foo> listener) {...}

处理程序可能会有
public void handleFoo(Foo foo) {...}

设置代码会初始化
provider.addFooListener(somehandler::handleFoo);

英文:

Stay away from common ancestors until you have a clear reason to deal with abstract events (like some logging, timing, queueing, serialization, etc...).

It's a lot simpler to code listeners as lambdas too. You would do well to think about classes of listeners actually, like Consumer&lt;Foo&gt; and Consumer&lt;Bar&gt;.

The event provider would implement something like
addFooListener(Consumer&lt;Foo&gt; listener) {...}

The handler might have
public void handleFoo(Foo foo) {...}

and the setup code would init
provider.addFooListener(somehandler::handleFoo);

答案2

得分: 2

有时我使用的一种模式是将监听器方法设置为空的默认方法然后在可以使用 lambda 创建的函数接口子类型中覆盖每个方法就像这样

    public interface IEventListener {
        default void onFoo(String string, Integer integer, ObjectB objectB){}
        default void onBar(Double d, ObjectA objectA){}
        interface OnFoo extends IEventListener {
            @Override void onFoo(String string, Integer integer, ObjectB objectB);
        }
        interface OnBar extends IEventListener {
            @Override void onBar(Double d, ObjectA objectA);
        }
    }

然后您可以使用匿名类来实现要接收的多个方法或者使用仅监听一个方法的 lambda 表达式

    object.addListener((OnBar)(d, a) -> System.out.println(d));

如果将来可能更改参数您仍然可以将其与问题中的 `FooEvent` 等事件对象一起使用这可能是一个不错的主意因为您可能只需向 `FooEvent` 添加一个字段而无需重新编写所有监听器实现

    
    default void onFoo(FooEvent event){}

我认为这在您有许多监听器需要每个监听特定事件子集的情况下更为合适但在我之前需要在一个地方处理所有事件的情况下我也使用过您问题中的第二种方法
英文:

A pattern I use sometimes is to have the listener methods be empty default methods and then override each of them in a functional interface subtype that can be created with a lambda, like this:

public interface IEventListener {
    default void onFoo(String string, Integer integer, ObjectB objectB){}
    default void onBar(Double d, ObjectA objectA){}
    interface OnFoo extends IEventListener {
        @Override void onFoo(String string, Integer integer, ObjectB objectB);
    }
    interface OnBar extends IEventListener {
        @Override void onBar(Double d, ObjectA objectA);
    }
}

Then you can use it either with an anonymous class that implements multiple methods you want to recieve or a lambda that just listens for one:

object.addListener((OnBar)(d, a) -&gt; System.out.println(d));

You could still use this with event objects like FooEvent from the question which could be a good idea if you may change the arguments in the future, since you might only need to add a field to FooEvent instead of rewriting all of your listener implementations.

default void onFoo(FooEvent event){}

I think this is better for when you have many listeners that each need to listen for a subset of the events, but I've also used your method 2 from the question before when I needed to process all of the events only in one place.

huangapple
  • 本文由 发表于 2020年10月26日 05:41:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/64529112.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定