开发者

java collection: get objects are modified, added and deleted?

开发者 https://www.devze.com 2023-03-16 06:35 出处:网络
Is there such a collection implemention can let us know what objects are newly added, modified or deleted comparing to a specific 开发者_StackOverflow中文版point?

Is there such a collection implemention can let us know what objects are newly added, modified or deleted comparing to a specific 开发者_StackOverflow中文版point?

I want to use such a collection to hold objects loaded from database, and bind it to user interface ,so user can add new object to it, delete items in it or modify some ones. when user click a save button , I need to persist changes to database, so I need to know the changed objects.


Here is my own solution, but I am not sure about whether it is very bad, please give me some advice.

interface :

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

Model Class must be extended from such a abstract class :

public abstract class DataObject {

    public abstract int dataHashCode();

}

implemention class :

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

}

test :

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

}

output :

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

edit: using hashCode is totally wrong, but maybe we can use MD5 or CRC32.


You can implement a custom collection that can easily track and log add, replace and delete operations but tracking and logging modifications on collection items is quite impossible..

The general idea: implement the List interface, add a delegate (a real list) and delegate all method calls to the internal list (or 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;
  }
}

But - the list can't track if someone uses a reference to item to modify its state after it has been added.


One way is to create your own collection implementing the Map interface and add a dirty flag to it. So that when you add or remove elements from the collection make the isDirty flag true and do the operation according to it.

if the existing object is changed then you need to have some different logic.


Tracking modifications means there has to be some ID that you can attach to each item, which also means your better choice is a Map instead of a Collection.

One example to do this is to subclass HashMap and intercept the put (for add/modify operations) and remove (for delete operations).

This is the general idea -- bottom line is you are most likely on your own with the implementation, unless somebody else can recommend a third-party API for this:

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


In my opinion you should not track changes in the collection but in the changed object itself. So have a changed flag as an instance field inside your object and set it to true when something changed and set it to false after you've written it to the database.

The problem in tracking inside the collection is that it is hard to keep track of modifications to objects already in the collection. Then you need something like a wrapper around each and every object that "informs" your collection when changes to that object happen. Too much in my opinion when this can be solved by tracking inside the objects itself. This objects' states can afterwards be used to filter the collection or whatever...

0

精彩评论

暂无评论...
验证码 换一张
取 消