Как наблюдать, когда пользовательский объект изменяется даже после его расширения - PullRequest
1 голос
/ 10 октября 2011

Итак, допустим, у меня есть пользовательский объект в Java:

   public class TestObject {

    private int value = 0;

        public TestObject(int value) {
                this.value = value;
        }

    public void increaseValue() {
        value++;
    }

    }

Теперь я хочу знать, когда этот объект был изменен.Или, более конкретно, я хочу знать, когда какие-либо из его полей изменились (в этом случае значение).Кроме того, если я расширяю TestObject, я все еще хочу иметь возможность прослушивать любые изменения полей, которые могут произойти с этим объектом, в том числе, если это изменение относится к новым полям, новые поля.

Я провел некоторое исследованиеи обнаружил множество слушателей, которые идут с Java, но все они, похоже, терпят неудачу в той области, где они требуют, чтобы вы вызывали слушателей в конце ваших методов.Например, incrementValue () также должен уведомить всех слушателей TestObject об изменении значения.Очевидно, это не работает для меня, потому что необходимо иметь расширяемость, и я не знаю, что если люди, которые наследуют от этого объекта, будут придерживаться требования, что они должны уведомлять слушателей.Не говоря уже о том, что для каждого метода мутатора кажется трудным запрограммировать, что

Если бы на этот предмет можно было пролить какой-то свет, это было бы очень полезно.

Ответы [ 3 ]

1 голос
/ 10 октября 2011

Не говоря уже о том, что программировать для каждого метода мутатора кажется трудным

Взгляните на Проект AspectJ .Этого очень легко достичь с производственным аспектом, используя pointcut для назначения поля .

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
1 голос
/ 10 октября 2011

Очевидно, это не работает для меня, потому что расширяемость обязательна, и я не знаю, что если люди, которые наследуют от этого объекта, будут придерживаться требования, что они должны уведомлять слушателей

Ваш подход не на правильном пути.

Вы не можете принудительно заставить производный класс сохранять инварианты базового класса, поскольку наследование может позволить классам-потомкам изменять реализацию таким образом, что они становятся недопустимыми с точки зрения родительского класса.

В вашем случае производный класс МОЖЕТ или МОЖЕТ не вызывать уведомление при модификации.

В подобных случаях вы должны моделировать arround Composition, а не Inheritence
Композиция против наследования

Для вашего примера:

class Value{    
    private int value;   
     public void increaseValue() {  
            value++;  
     }  
}

Значение знает, как увеличить себя.

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();  
       }  
    }

Таким образом, весь код будет выглядеть следующим образом:

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);    

Итак, теперь выгода в том, что использование объектов осуществляется через владельца.
Тогда уведомление будетслучается.

1 голос
/ 10 октября 2011

Вы можете использовать подход, который Hibernate использует , т. Е. Инструмент / прокси ваших классов для добавления дополнительной (слушающей) логики вокруг геттеров и сеттеров ваших POJO.Но тогда вам нужно убедиться, что все используют только прокси-классы.

...