Search code examples
javaeventslambdafunctional-interface

Implementing a proper C# event (not delegate) in java


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.


Solution

  • As mentioned by @Jon Skeet in the comments, changing the code as below meets my requirement:

    EventPubisher.java

    public class EventPublisher {
    
        private final Event ValueUpdatedEvent = new Event();
    
        public void addEventHandler(Event.EventHandler eventHandler){
            ValueUpdatedEvent.add(eventHandler);
        }
    
        public void removeEventHandler(Event.EventHandler eventHandler){
            ValueUpdatedEvent.remove(eventHandler);
        }
    
        public void UpdateValue(){
            ValueUpdatedEvent.invoke();
        }
    }
    

    EventConsumer.java

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