ListenersThe Listeners library allows you to geatly simplify the code you add to support listeners in your code. It contains listener collections that provide a special proxy object. Invoking a method on the proxy automatically invokes the method on all contained listeners. As a result, there is no longer need to implement 'fire' methods, your code is simplified, and its correctness is guaranteed. The code is provided under the Apache license. What you win The library allows you to delegate the proper handling of listeners to specialized code and to concentrate on more important matters. Basically you win in the following areas:
[Listeners library]
[Javassist library
web]
[Listeners source]
[Listeners javadoc
zip]
|
||||||||||||
|
Example Using the provided library, a class can support listeners of a given type by simply defining the container where the listeners will be kept and by defining a 'proxy' object of the same type as the listeners (this is optional, but simplifies the listener invocation code). For example:
private IListenerManager _keyLMgr = new GenListenerManager(KeyListener.class);
private KeyListener _keyLProxy = (KeyListener) _keyLMgr.getProxy();
public void addListener(KeyListener lst) { _keyLMgr.addListener(lst); }
public void removeListener(KeyListener lst) { _keyLMgr.removeListener(lst); }
Once this is done, the listeners can be invoked whenever necessary by simply
calling the corresponding function on the proxy object, for example:
_keyLProxy.keyPressed(event);
_keyLProxy.keyReleased(event);
_keyLProxy.keyTyped(event);
This will automatically invoke the corresponding functions of all listeners
contained by the ListenerManager.
In contrast, here is the code one typically writes to handle listeners. First define the listener container and its associated methods:
private List _arrListeners = new ArrayList();
public synchronized void addListener(KeyListener objListener) {
// perhaps make sure there are no duplicates here
if (!_arrListeners.contains(objListener))
_arrListeners.add(objListener);
}
public synchronized void removeListener(KeyListener objListener) {
_arrListeners.remove(objListener);
}
Then define a 'fire' method for each method of the interface:
private synchronized void fireKeyPressed(KeyEvent event) {
for (Iterator it = _arrListeners.iterator(); it.hasNext();) {
KeyListener listener = (KeyListener) it.next();
listener.keyPressed(event);
}
}
private synchronized void fireKeyReleased(KeyEvent event) {
for (Iterator it = _arrListeners.iterator(); it.hasNext();) {
KeyListener listener = (KeyListener) it.next();
listener.keyReleased(event);
}
}
private synchronized void fireKeyTyped(KeyEvent event) {
for (Iterator it = _arrListeners.iterator(); it.hasNext();) {
KeyListener listener = (KeyListener) it.next();
listener.keyTyped(event);
}
}
The listeners can then be invoked by calling the corresponding 'fire' method:
fireKeyPressed(event);
fireKeyReleased(event);
fireKeyTyped(event);
|
||||||||||||
|
Performance The ListenerManager behaviour is defined in the IListenerManager interface. There are two implementations of that interface provided -- GenListenerManager that uses the Javassist library to generate the necessary proxy class in runtime via byte-code manipulation, and RefListenerManager that uses the built in Java reflection facilities to achieve the same task. Both implementations behave identically, but differ in performance and in the required libraries (GenListenerManager requires Javassist, RefListenerManager does not require additional libraries) Here is a comparison of the invocation speeds different solutions offer. The evaluation is time for 50 000 000 invocations, faster is better:
To summarize, GenListenerManager performs better than the typical ways in which listeners are handled. RefListenerManager is much slower, but it is a good fit for cases where additional libraries are not wanted and performance is not that critical. |
||||||||||||