Коллекция Java: получить объекты изменены, добавлены и удалены? - PullRequest
2 голосов
/ 29 июня 2011

Существует ли такая реализация коллекции, которая может сообщить нам, какие объекты добавляются, изменяются или удаляются по сравнению с определенной точкой?

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


Вот мое собственное решение, но я не уверен, что оно очень плохое.Пожалуйста, дайте мне несколько советов.

интерфейс:

import java.util.Collection;

/**
 * @author ggfan@amarsoft
 *
 */
public interface DataObjectsMonitor {

    /**
     * take a snapshot for comparing
     */
    public void snapshot();

    /**
     * 
     * @return Objects that are modified comparing to those ones before {@link #snapshot()} last called
     */
    public Collection<?> getmodifiedObjects();

    /**
     * 
     * @return Objects that are deleted comparing to those ones before {@link #snapshot()} last called
     */
    public Collection<?> getDeletedObjects();

    /**
     * 
     * @return Objects that are added comparing to those ones before {@link #snapshot()} last called
     */
    public Collection<?> getAddedObjects();
}

Класс модели должен быть расширен из такого абстрактного класса:

public abstract class DataObject {

    public abstract int dataHashCode();

}

Класс реализации:

public class DataObjectListMonitor<T extends DataObject> extends ArrayList<T> implements DataObjectsMonitor {

    private static final long serialVersionUID = 1L;

    private Map<T, Integer> oldVersion = new HashMap<T, Integer>();

    public void snapshot() {
        oldVersion.clear();
        for(T t : this){
            oldVersion.put(t, new Integer(t.dataHashCode()));
        }
    }

    public Collection<T> getmodifiedObjects() {
        ArrayList<T> modified = new ArrayList<T>();
        for(T t : oldVersion.keySet()){
            if(this.contains(t) && t.dataHashCode() != oldVersion.get(t)){
                modified.add(t);
            }
        }
        return modified;
    }

    public Collection<T> getDeletedObjects() {
        ArrayList<T> deleted = new ArrayList<T>();
        for(T t : oldVersion.keySet()){
            if(!this.contains(t)){
                deleted.add(t);
            }
        }
        return deleted;
    }

    public Collection<T> getAddedObjects() {
        ArrayList<T> added = new ArrayList<T>();
        for(T t : this){
            if(!oldVersion.keySet().contains(t)){
                added.add(t);
            }
        }
        return added;
    }

}

тест:

public class Model extends DataObject {
    private String id;

    private String name;

    public String toString() {
        return "Model [id=" + id + ", name=" + name + "]";
    }

    public Model(String id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int dataHashCode() {
        int dataHashCode = 0;
        if(id != null){
            dataHashCode += id.hashCode();
        }
        if(name != null){
            dataHashCode += name.hashCode();
        }
        return dataHashCode;
    }

    public static void main(String[] args){
        DataObjectListMonitor<Model> data = new DataObjectListMonitor<Model>();
        Model m1 = new Model("m1", "model 1");
        Model m2 = new Model("m2", "model 2");
        Model m3 = new Model("m3", "model 3");
        Model m4 = new Model("m4", "model 4");
        Model m5 = new Model("m5", "model 5");
        data.add(m1);
        data.add(m2);
        data.add(m3);
        data.add(m4);
        data.add(m5);
        data.snapshot();
        Model m6 = new Model("m6", "model 6");
        data.add(m6);
        m3.setName("model 3 changed");
        m3.setName("model 3");
        data.remove(m5);
        m1.setName("model 1 chaned");
        for(Model m : data.getAddedObjects()){
            System.out.println("added : " +  m);
        }

        for(Model m : data.getDeletedObjects()){
            System.out.println("deleted : " + m);
        }

        for(Model m : data.getmodifiedObjects()){
            System.out.println("modified : " + m);
        }
    }

}

выход:

added : Model [id=m6, name=model 6]
deleted : Model [id=m5, name=model 5]
modified : Model [id=m1, name=model 1 chaned]

edit: использование hashCode совершенно неверно, но, возможно, мы можем использовать MD5 или CRC32.

Ответы [ 4 ]

4 голосов
/ 29 июня 2011

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

Общая идея: реализовать интерфейс Listдобавьте делегата (реальный список) и делегируйте все вызовы методов во внутренний список (или set, map, queue, ...):

public class LoggingList implements List {
  private List delegate = new ArrayList();
  private List<ChangeEvent> history = new ArrayList<ChangeEvent>();

  // ...

  @Override
  public boolean add(Object item) {
    boolean success = delegate.add(item);
    if (success) {
     history.add(new ChangeEvent(Type.ADD, item));
    }
    return success;
  }
}

Но - список не может отследить, если кто-тоиспользует ссылку на item для изменения своего состояния после добавления.

1 голос
/ 29 июня 2011

Отслеживание изменений означает, что должен быть какой-то идентификатор, который вы можете прикрепить к каждому элементу, что также означает, что ваш лучший выбор - Map вместо Collection.

Один из примеров для этого:подкласс HashMap и перехватывать put (для операций добавления / изменения) и remove (для операций удаления).

Это общая идея - суть в том, что вы, скорее всего, на вашемпокончим с реализацией, если кто-то другой не может порекомендовать сторонний API для этого:

  Map<K, V> items = new HashMap<K, V>() {
    public V put(K key, V value) {
      if (containsKey(key))
        modified.put(key, value);
      else
        created.put(key, value);

      return super.put(key, value);
    }

    public V remove(Object key) {
      if (containsKey(key))
        deleted.put((K) key, get(key));

      return super.remove(key);
    }
  };
1 голос
/ 29 июня 2011

По моему мнению, вы не должны отслеживать изменения в коллекции, но в самом измененном объекте.Так что имейте changed flag в качестве поля экземпляра внутри вашего объекта и установите его на true, когда что-то изменилось, и установите его на false после записи в базу данных.внутри коллекции трудно отслеживать изменения объектов, уже находящихся в коллекции.Затем вам нужно что-то вроде обертки вокруг каждого объекта, который «сообщает» вашей коллекции, когда происходят изменения в этом объекте.Слишком много, на мой взгляд, когда это можно решить путем отслеживания внутри самих объектов.Впоследствии состояния этих объектов могут быть использованы для фильтрации коллекции или чего-либо еще ...

1 голос
/ 29 июня 2011

Один из способов - создать собственную коллекцию, реализующую интерфейс Map, и добавить в нее флаг dirty. Так что, когда вы добавляете или удаляете элементы из коллекции, установите для флага isDirty значение true и выполните соответствующую операцию.

если существующий объект изменен, вам нужна другая логика.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...