Click here to Skip to main content
15,395,181 members
Articles / Programming Languages / Java
Tip/Trick
Posted 26 Mar 2017

Stats

9.9K views
3 bookmarked

C# Like Event Handlers Pattern in Java

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
26 Mar 2017CPOL1 min read
Simulating C# event handlers in Java

Introduction

For those of us who come from the C# world, sometimes it can be a bit difficult to deal with the way events are handled in Java with listeners. This pattern is implemented to solve that problem in a familiar way to .NET.

Background

A few weeks ago, for work reasons, I had to go to the Java world and leave behind .NET. Everything was fine until I had to face the listeners, although it is a fairly interesting (observer) pattern at times that can be a bit cumbersome. For this, I solved my problem in this way (implementing a pattern similar to the C # eventhandlers), although it is a solution that may not necessarily be definitive but could serve you on more than one occasion.

Using the Code

Thanks to @FunctionalInterfaces, it is possible to build a kind of .NET delegate.

What is a functional interface?

Java
@FunctionalInterface
public interface IEvent<TEventArgs extends Object> {
    void invoke(Object source, TEventArgs eventArgs);
}

Now, we can define a reutilizable EventHandler class for event manage:

Java
public class EventHandler<TEventArgs>
{
    private ArrayList<IEvent<TEventArgs>> eventDelegateArray = new ArrayList<>();
    public void subscribe(IEvent<TEventArgs> methodReference)
    {
        eventDelegateArray.add(methodReference);
    }
    public void unSubscribe(IEvent<TEventArgs> methodReference)
    {
        eventDelegateArray.remove(methodReference);
    }
    public void invoke(Object source, TEventArgs eventArgs)
    {
        if (eventDelegateArray.size()>0)
            eventDelegateArray.forEach(p -> p.invoke(source, eventArgs));
    }
    public void close()
    {
        if (eventDelegateArray.size()>0)
            eventDelegateArray.clear();
    }
}

This EventHanlder class allows us to subscribe, un-subscribe, invoke, clean up resources of our defined event.

For purposes of testing our code, we will create an event producing class and a consumer class (subscriber) of our event.

Java
public class DummyEventProducer
{
    // The event
    public EventHandler<String> myEvent = new EventHandler<>();

    public void onMyEvent(String A)
    {
        myEvent.invoke(this, A);
    }
}
Java
public class DummySubscriber {

    // The method will be subscribed to the event
    public void methodCallWhenEventGetTriggered(Object source, String eventArgs)
    {
        System.out.println("event fired with eventargs: " + eventArgs);
    }
}

Now the main entry point of our test app:

Java
public class Main {

    public static void main(String[] args)
    {
        // A dummy producer
        DummyEventProducer producer = new DummyEventProducer();

        // A dummy subscribers
        DummySubscriber testingInstanceA = new DummySubscriber();
        DummySubscriber testingInstanceB = new DummySubscriber();
        DummySubscriber testingInstanceC = new DummySubscriber();

        // We create weak event references because we want to un-subscribe later
        IEvent<String> EventSink1 = 
        	testingInstanceA::methodCallWhenEventGetTriggered;
        IEvent<String> EventSink2 = 
        	testingInstanceB::methodCallWhenEventGetTriggered;
        IEvent<String> EventSink3 = 
        	testingInstanceC::methodCallWhenEventGetTriggered;

        // subscribe to the event on dummy producer
        producer.myEvent.subscribe(EventSink1);
        producer.myEvent.subscribe(EventSink2);
        producer.myEvent.subscribe(EventSink3);

        // fire the event on producer
        producer.onMyEvent("Hola MUNDO with decoupled subscriptions!");

        // unsubscribe to the event on dummy producer
        producer.myEvent.unSubscribe(EventSink1);
        producer.myEvent.unSubscribe(EventSink2);
        producer.myEvent.unSubscribe(EventSink3);

        // fire the event on producer again
        producer.onMyEvent("Hola MUNDO! with no events subscriptions :(");

        // IF YOU DON CARE ABOUT UNSUBSCRIBE 
        // YOU CAN CREATE STRONG EVENTS REFERENCES DIRECTLY TO THE SUBSCRIBER
        producer.myEvent.subscribe(testingInstanceA::methodCallWhenEventGetTriggered);
        producer.myEvent.subscribe(testingInstanceB::methodCallWhenEventGetTriggered);
        producer.myEvent.subscribe(testingInstanceC::methodCallWhenEventGetTriggered);

        // fire the event on producer again
        producer.onMyEvent("Hola MUNDO! with strong references 
                           subscriptions (cannot be un-subscribed one by one");

        // clear all subscriptions
        producer.myEvent.close();

        // fire the event on producer again
        producer.onMyEvent("Hola MUNDO! again");
    }
}

And that's it! I hope it will be useful for you.

Points of Interest

I do not recommend using strong references as they can generate memory leaks, but instead, try to use weak references, especially when it comes to events.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Danilow
United States United States
No Biography provided

Comments and Discussions

 
QuestionCould you not have used something like this Pin
Sacha Barber27-Mar-17 0:40
MemberSacha Barber27-Mar-17 0:40 
AnswerRe: Could you not have used something like this Pin
Danilow18-Apr-17 10:35
MemberDanilow18-Apr-17 10:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.