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?
@FunctionalInterface
public interface IEvent<TEventArgs extends Object> {
void invoke(Object source, TEventArgs eventArgs);
}
Now, we can define a reutilizable EventHandler
class for event manage:
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.
public class DummyEventProducer
{
public EventHandler<String> myEvent = new EventHandler<>();
public void onMyEvent(String A)
{
myEvent.invoke(this, A);
}
}
public class DummySubscriber {
public void methodCallWhenEventGetTriggered(Object source, String eventArgs)
{
System.out.println("event fired with eventargs: " + eventArgs);
}
}
Now the main entry point of our test app:
public class Main {
public static void main(String[] args)
{
DummyEventProducer producer = new DummyEventProducer();
DummySubscriber testingInstanceA = new DummySubscriber();
DummySubscriber testingInstanceB = new DummySubscriber();
DummySubscriber testingInstanceC = new DummySubscriber();
IEvent<String> EventSink1 =
testingInstanceA::methodCallWhenEventGetTriggered;
IEvent<String> EventSink2 =
testingInstanceB::methodCallWhenEventGetTriggered;
IEvent<String> EventSink3 =
testingInstanceC::methodCallWhenEventGetTriggered;
producer.myEvent.subscribe(EventSink1);
producer.myEvent.subscribe(EventSink2);
producer.myEvent.subscribe(EventSink3);
producer.onMyEvent("Hola MUNDO with decoupled subscriptions!");
producer.myEvent.unSubscribe(EventSink1);
producer.myEvent.unSubscribe(EventSink2);
producer.myEvent.unSubscribe(EventSink3);
producer.onMyEvent("Hola MUNDO! with no events subscriptions :(");
producer.myEvent.subscribe(testingInstanceA::methodCallWhenEventGetTriggered);
producer.myEvent.subscribe(testingInstanceB::methodCallWhenEventGetTriggered);
producer.myEvent.subscribe(testingInstanceC::methodCallWhenEventGetTriggered);
producer.onMyEvent("Hola MUNDO! with strong references
subscriptions (cannot be un-subscribed one by one");
producer.myEvent.close();
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.