How to observe when a custom object changes even after it's extended
So let's say I have a custom object in java:
public class TestObject {
private int value = 0;
public TestObject(int value) {
this.value = value;
}
public void increaseValue() {
value++;
}
}
Now I want to know when this object is modified. Or more specifically, I want to know when any of it's fields have changed (in this case value). Furthermore, if I extend TestObject, I still want to be able to listen to any field changes that might happen to that object, including if that change is to a new field new fields.
I've done some research and found of variety of listeners that come with java, but they all seem to fail in the area that they require you to开发者_Go百科 put calls to the listeners at the end of you're methods. For example, increaseValue() would also have to notify all of the listeners to the TestObject that value had changed. Obviously this doesn't work for me because extensibility is a must have and I do not know that if people who inherit from that object will adhere to the requirement that they must notify listeners. Not to mention, it seems like a pain to have to program that for each mutator method
If any light could be shed on this subject it would be greatly appreciated.
You can use approach that Hibernate uses i.e. instrument/proxy your classes to add additional (listener) logic around your POJOs' getters and setters. But then you need to ensure that all use only proxied classes.
Not to mention, it seems like a pain to have to program that for each mutator method
Take a look at The AspectJ Project. You could achieve this very easily with production aspect using a pointcut for field assignment.
public privileged aspect TestObjectObserver {
before(Object o) : set(* TestObject.*) && args(o) {
// notify listeners
}
}
// runs before field assignment to any field of TestObject. The value to be
// assigned is converted to an object type (int to Integer, for
// example) and named o in the body
// the aspect needs to be declared privileged so access private fields
Obviously this doesn't work for me because extensibility is a must have and I do not know that if people who inherit from that object will adhere to the requirement that they must notify listeners
Your approach is not in the correct path.
You can not enforce a derived class to keep the base's class invariants since inheritance can allow descendant classes to alter implementation in a way that makes them invalid from the viewpoint of the parent class.
In your case the derived class MAY or MAY not call the notification upon modification.
In cases like this you should model arround Composition
and not Inheritence
Composition vs Inheritence
For your example:
class Value{
private int value;
public void increaseValue() {
value++;
}
}
Value knows how to increment itself.
class ValueHolder extends Observable {
private Value theValue;
public ValueHolder(Value v){
theValue = v;
}
public void modifyValue(String methodName)(){
Method method = theValue.getClass().getMethod(methodName, null);
method.invoke(theValue,null);//Since it has no args
setChanged();
notifyObservers();
}
}
So all the code will be as follows:
ValueHolder vh = new ValueHolder(new Value(10));
//registration of listeners
vh.modifyValue("increaseValue");
//So if you extend the Value
class DerivedValue extends Value{
private int y;
public void increaseY() {
y++;
}
}
ValueHolder vh = new ValueHolder(new DerivedValue());
//registration of listeners
vh.modifyValue("increaseY);
So the catch now is that the usage of the objects are via the holder.
Then the notification will happen.
精彩评论