I created a class to handle these requirements in a generic way. I thought of this new "value class" as containing a capricious value, and so called it Fickle, which is a parameterized class. It is not synchronised, so beware when multithreading.
Here is the code:
import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
public class Fickle<T>
{
private T _value;
private final Set<OnChangeListener<T>> _listeners;
public Fickle(final T value)
{
_value = value;
_listeners = Collections.newSetFromMap(
new WeakHashMap<OnChangeListener<T>, Boolean>());
}
public void addOnChangeListener(final OnChangeListener<T> listener)
{
_listeners.add(listener);
}
public void setValue(final T newValue)
{
_value = newValue;
for (OnChangeListener<T> l : _listeners)
if (l != null)
l.onChangeEvent(newValue);
}
public T getValue()
{
return _value;
}
public interface OnChangeListener<T>
{
void onChangeEvent(T newValue);
}
}
As you can see I have used a Set made from a WeakHashMap to store the event listeners. This is to ensure that Fickle objects don't create memory leaks. As the reference to the listener is weak, when a listener object is no longer in use anywhere else in the code then it will automatically be removed from the set. This is a very cool Java feature. However, what this means is that you must have a strong (normal) reference to the listener object, otherwise it will be deleted.
Here is an example of how to use the Fickle class:
class MrsClass
{
private float _doubleVal;
public MrsClass(final Fickle<Float> capVal)
{
// Initialize the member variable.
setVal(capVal.getValue());
// Handle the on change event.
capVal.addOnChangeListener(new Fickle.OnChangeListener<Float>()
{
public void onChangeEvent(Float newValue)
{
setVal(newValue);
}
});
}
private void setVal(float val)
{
_doubleVal = val * 2.0f;
}
public float getDoubleVal()
{
return _doubleVal;
}
}
class MrMain
{
public static void main(String[] args)
{
Fickle<Float> val;
val = new Fickle<Float>(1.0f);
MrsClass mrs = new MrsClass(val);
float doubled = mrs.getDoubleVal(); // should equal 2.0f
val.setValue(3.5f);
doubled = mrs.getDoubleVal(); // should equal 7.0f
// By dereferencing the MrsClass object the
// listener will be automatically removed from
// the listener Set by the WeakHashMap class.
mrs = null;
}
}
So this is effectively an encapsulation of the Observer pattern.