英文:
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<Foo> and Consumer<Bar>.
The event provider would implement something like
addFooListener(Consumer<Foo> 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) -> 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论