gpt4 book ai didi

java - 在 java 中实现正确的 C# 事件(而不是委托(delegate))

转载 作者:行者123 更新时间:2023-12-02 09:47:02 24 4
gpt4 key购买 nike

正如 this 中已经提到的SO 答案和同一问题中的其他帖子,C# 委托(delegate)可以使用接口(interface)或 Java FuncationInterfaces 来实现。

但是,我希望在 Java 中实现适当的事件模型而不是委托(delegate)模型。简单介绍一下两者的区别,请参见this 。尤其是第一条评论。

以下是我迄今为止尝试过的:

事件.java

public class Event {
public interface EventHandler{
void invoke();
}

private Set<EventHandler> mEventHandlers = new HashSet<>();

public void add(EventHandler eventHandler){
mEventHandlers.add(eventHandler);
}

public void remove(EventHandler eventHandler){
mEventHandlers.remove(eventHandler);
}

public void invoke(){
for(EventHandler eventHandler : mEventHandlers){
if(eventHandler!=null) {
eventHandler.invoke();
}
}
}
}

EventPubisher.java

public class EventPublisher {

public Event ValueUpdatedEvent;

public void UpdateValue(){
ValueUpdatedEvent.invoke();
}
}

EventConsumer.java

public class EventConsumer {
EventPublisher ep = new EventPublisher();

public EventConsumer(){
ep.ValueUpdatedEvent.add(this::ValueUpdatedEventHandler);
}

private void ValueUpdatedEventHandler(){
// do stuff
}
}

这种设计的问题是我也可以编写如下代码:

public class EventConsumer {
.....
private void abuse(){
ep.ValueUpdatedEvent.invoke();
}
}

这尤其受到事件的限制。该事件只能从声明类引发,而不是从外部引发。

最佳答案

如果您想避免在发布商上使用添加/删除方法,可以使用下面的代码吗?它使用两个类(Event 和 EventImpl)来分隔添加/删除和调用,因此可以将调用设为发布者私有(private)。它是通用的,因此可以使用不同的监听器接口(interface)。

这段代码节省了很多重复的样板,但是你认为它会被认为是惯用的@JonSkeet吗?

以下是事件类:

class Event<TListener> {
private final Set<TListener> listeners;

Event(Set<TListener> listeners) {
this.listeners = listeners;
}

public void add(TListener listener) {
listeners.add(listener);
}

public void remove(TListener listener) {
listeners.remove(listener);
}
}

class EventImpl<TListener> {
private Set<TListener> listeners = new HashSet<>();
private Event<TListener> event = new Event<>(listeners);

Event<TListener> getEvent() {
return event;
}

interface Invoker<TListener> {
void invoke(TListener listener);
}

public void invoke(Invoker<TListener> invoker) {
for (TListener listener : listeners){
if (listener != null) {
invoker.invoke(listener);
}
}
}
}

下面是发布者和订阅者的示例,其中包含一些测试代码来执行它们:

class MyEventPublisher {
interface Listener {
void listenToThis(int intArg, String stringArg, Object... etc);
}

private EventImpl<Listener> eventImpl = new EventImpl<>();

Event<Listener> getEvent() {
return eventImpl.getEvent();
}

void somethingCausingAnEvent() {
eventImpl.invoke(
listener -> listener.listenToThis(1, "blah", 10,11, 12));
}
}

class MyEventSubscriber {
private String eventRecord = "";

MyEventSubscriber(MyEventPublisher publisher) {
publisher.getEvent().add(
(intArg, stringArg, etc) -> eventRecord += intArg + stringArg + Arrays.toString(etc));
}

String getEventRecord() {
return eventRecord;
}
}

public class TestEvents {
@Test
public void testEvent() {
MyEventPublisher p = new MyEventPublisher();
MyEventSubscriber s = new MyEventSubscriber(p);
p.somethingCausingAnEvent();
assertEquals("1blah[10, 11, 12]", s.getEventRecord());
}
}

关于java - 在 java 中实现正确的 C# 事件(而不是委托(delegate)),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56567562/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com