PropertyChangeSupport и метод equals
-
05-07-2019 - |
Вопрос
Я постараюсь объяснить мою проблему как можно яснее :). Я использую PropertyChangeSupport для уведомления зарегистрированных представлений об изменениях в свойствах. Одним из свойств является объект, свойства которого меняются каждые секунды просмотра. Я не хочу создавать для этого конкретного объекта новый экземпляр каждый раз, когда он обновляется (чтобы propertychangelistener заметил это изменение), поэтому я написал свой собственный метод equals, в котором я пропускаю сравнение для себя.
@Override
public boolean equals(Object item) {
// do not compare
// if (this == item) { return true; }
if (!(item instanceof TransferQueueItem) ||
item == null) {
return false;
}
TransferQueueItem newItem = (TransferQueueItem) item;
boolean value =
// ommited... properties comparation
return value;
}
К сожалению, это не имеет эффекта, который я искал. Если я создаю копию объекта и запускаю метод изменения свойства, он работает нормально.
Что мне здесь не хватает?
- Изменить
Я понял, что, поскольку я использую один и тот же экземпляр, а не его копию, свойства указывают на одно и то же место, поэтому сравнение всегда будет выполнено. Есть ли обходной путь к этому (помимо создания копии). Или как плохо создавать копию объекта каждую секунду, например.
Решение
Вы всегда должны возвращать true
, чтобы сообщить PropertyChangeSupport
, что ваш объект не изменился. Но это означает, что equals ()
не работает для всех объектов этого класса (например, вы больше не можете использовать их в наборах или картах).
Лучшим способом было бы иметь специальный метод firePropertyChange ()
для этого типа объекта, который выполняет специальную обработку. Таким образом, вы даже можете избежать создания экземпляра PropertyChangeEvent
. Вот пример для обработки BigDecimal
(где equals ()
вообще не работает):
protected transient PropertyChangeSupport changeSupport = null;
public void addPropertyChangeListener (String propertyName, PropertyChangeListener listener)
{
if (changeSupport == null)
changeSupport = new PropertyChangeSupport (this);
changeSupport.addPropertyChangeListener (propertyName, listener);
}
public void firePropertyChange (String propertyName, BigDecimal oldValue, BigDecimal newValue)
{
if (changeSupport == null)
return;
if (oldValue != null && newValue != null && oldValue.compareTo (newValue) == 0) {
return;
}
changeSupport.firePropertyChange(new PropertyChangeEvent(this, propertyName,
oldValue, newValue));
}
[EDIT] Что вы делаете, это совсем другое: у вас есть родитель и ребенок, и вы хотите, чтобы слушатели parent получали события, когда child изменяется. р>
Правильный подход здесь - добавить PropertyChangeSupport
в child . Когда дочерний элемент добавляется к родительскому элементу, родительский компонент должен установить необходимые дочерние элементы в дочернем элементе. Когда событие вызывается, оно должно запустить второе событие, которое информирует слушателей parent об изменении в child (родитель должен пересылать события). р>
Другие советы
это случай цепочки измененных свойств:
TransferQueueItem должен запустить свои собственные PropertychangeEvents, которые должны прослушиваться TransferQueue, в который вставлено
И в ответ TransferQueue должен уведомить своих слушателей, что принадлежащий элемент изменился.
Каждый раз, когда у меня возникает такая проблема, когда объект должен перезапускать события, я использую это соглашение (моей рабочей команды):
1 Объект может запускать только события, источником которых является сам.
2 Если ему нужно делегировать событие, оно запускает событие, подобное следующему: new PropertyChangeEvent (this, " DELEGATED_EVENT " ;, null, receiveEvent). Чтобы слушатели могли следить за цепочкой событий. Р>
У меня есть статический метод в классе Util, который следует за цепочкой событий и возвращает самое первое событие, свойство whick не является " DELEGATED_EVENT "