I been inspired by Signals events pattern in AS3, that replace the native events of flash. And it's work much better, both in performance and readability.
So I am trying to implement it in Java.
the main Idea of this pattern is that you are working with objects instead of types, saving by this the time to find the "Dispatcher" class to handle your event dispatch.(Dispatching event is sending event to all the listeners)
So lets jump into the code: In this sample I will create AlarmManager and handle his alarm event.
First we need to create our Interface for this event
public interface IAlarmEvent {
void alarmEventHandler(String alert);
}
Now the event itself:
public class AlarmEvent extends Signal<IAlarmEvent> implements IAlarmEvent {
public void alarmEventHandler(String alert) {
dispatch("alarmEventHandler", alert);
}
}
And here is the AlarmManger:
public class AlarmManager {
public final AlarmEvent alarmEvent = new AlarmEvent();
public void init(){
// Dispatching the event
alarmEvent.alarmEventHandler("Wake up");
}
}
Here is an Activity who is listening for this event:
public class MainActivity extends Activity implements IAlarmEvent{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AlarmManager alarmManager = new AlarmManager();
alarmManager.alarmEvent.addListener(this);
alarmManager.init();
}
public void alarmEventHandler(String alert) {
Log.d("MyLog", "Event : " + alert);
}
}
And here is how I wrote the Signal class
public abstract class Signal<T> {
private LinkedHashMap<T, T> listeners = new LinkedHashMap<T, T>();
protected void dispatch(String methodName, Object...arguments){
Set<T> keySet = listeners.keySet();
if(keySet.size() == 0){
return;
}
Iterator<T> iterator = keySet.iterator();
Method method = null;
do{
T listener = iterator.next();
if(method == null){
try {
Class<?>[] classes = new Class<?>[arguments.length];
for(int i = 0; i < arguments.length; i++){
classes[i] = arguments[i].getClass();
}
method = listener.getClass().getMethod(methodName, classes);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
try {
method.invoke(listener, arguments);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}while(iterator.hasNext());
}
public void addListener(T listener) {
listeners.put(listener, listener);
}
public void removeListener(T listener) {
listeners.remove(listener);
}
}
This pattern is:
- fast - no need to search for type and trigger the eventDispatcher, it's done immediately.
- have great readability - Just by looking at the class you know exactly what events he dispatch, and how each event looks like.
However it's not working well. If I am using primitives for my interface, the Signal fails to find the Method and invoke it. And I don't like the idea passing the Method name to the signal. Any Ideas how to improve this? And what do you think about this pattern?