As already mentioned in this SO answer and the other posts in the same question, C# delegates can be implemented using interfaces or Java FuncationInterfaces.
However I am looking to implement a proper event model and not a delegate model in Java. For a brief on the difference of the two, please see this. Especially the first comment.
Below is what I have tried so far:
Event.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
}
}
The problem with this design is that I can write code like below as well:
public class EventConsumer {
.....
private void abuse(){
ep.ValueUpdatedEvent.invoke();
}
}
And this is particularly what events restrict. The event should be raised only from the declaring class and not from outside.
If you wanted to avoid the add/remove methods on your publisher, could you use the code below? It uses two classes (Event and EventImpl) to separate the add/remove and the invoke, so invoke can be made private to the publisher. It is generic so different listener interfaces can be used.
This code saves a lot of duplicated boilerplate, but do you think it would it be considered idiomatic @JonSkeet?
Here are the event classes:
And here is an example of a publisher and subscriber with some test code to exercise them:
As mentioned by @Jon Skeet in the comments, changing the code as below meets my requirement:
EventPubisher.java
EventConsumer.java