如何跟踪对象图的更改?

时间:2011-01-26 18:20:18

标签: java

我正在处理一些代码,当对象中的某些内容发生变化时,我想要检测这些代码。跟踪更改的最简单方法之一是保留对象的旧副本。但是,看起来获得深度图的副本可能很困难。这是我试过的:


public class Old{
    protected Old old;
    protected List stuff;

    //Needed for JUnit
    public Old(){
    }

    public Old(List stuff){
        this.stuff=stuff;
        old=this;
    }

    public void add(){
        stuff.add(2);
    }

    public void match(){
        System.out.printf("old:%d\nnew:%d\n",old.getStuff().size(),stuff.size());
    }

    public List getStuff(){
        return new ArrayList(stuff);
    }

    @Test
    public void testOld(){
        List list=new ArrayList();
        list.add(1);
        Old thing=new Old(list);
        thing.add();
        thing.match();
    }
}

输出:

old:2
new:2

因此,默认情况下old=this似乎不会创建深层副本。我真正想要的是跟踪对该列表的更改以及可能的对象图。还有其他一些简单的选择吗?

6 个答案:

答案 0 :(得分:2)

根据您的具体要求,这可能有效

  1. 控制访问将对象更改为setter(即使用适当的封装)
  2. 添加一个修订数组,这是一个字符串数组
  3. 每次调用setter或更改对象的任何其他方法时,调用toString并存储结果
  4. 这很简单,但可能适合您的需求,并有以下优点:

    1. 您可以将其抽象为基类以供重用。
    2. 您可以测试字符串相等性,以便不记录不会更改任何内容的集合。 (将当前更改与修订数组中的最后一个元素进行比较)
    3. 你可能会非常喜欢并拥有像'recordChanges'这样的属性,所以录音只在真实时发生(可能是默认值)。这样,如果要连续执行多组操作,则可以一次记录所有更改,而不是每组记录。 (即创建一个startRecording和stopRecording方法,当你startRecording记录当前状态时)
    4. 它有以下额外的工作:

      1. 您必须实现一个可靠的toString和hashCode。无论如何你可能要做的事情

      2. 如果您连续调用一堆集合可能会很慢,但您可以通过上面的建议3来缓解这一点。

      3. 最后,如果你真的很喜欢,你可以实现四人帮Momento pattern。这对你所需要的东西来说可能有些过分(因为它可以让你恢复到以前的状态),但仍然会很棒。

答案 1 :(得分:0)

您正在将ArrayList与同一ArrayList的副本进行比较而不进行更改。无论副本是否很深,它们总是具有相同数量的元素。

是的,在这种情况下,ArrayList保存引用,如果在ArrayList的构造函数中传递一个列表,它将不会创建新对象,而是对对象具有相同的引用。

答案 2 :(得分:0)

您可以考虑使用观察者。您可以创建一个Observer类,当发生更改时,该类会被对象通知。也许你可以保留旧的和新的价值观。然后,您可以将观察者添加到要跟踪的每个对象。您可以详细了解此选项herehere

答案 3 :(得分:0)

您只复制了指向引用的指针。 list和old.stuff都指向同一个对象。对列表所做的任何更改都将反映在old.stuff中,反之亦然。您想使用Collections.copy制作List的副本。然后对list的任何更改都不会反映在old.stuff中的引用(对于差异List对象)中。有关详细信息,请查看this answer

答案 4 :(得分:0)

在人们指出旧的可能指向新的之后,我添加了一个复制构造函数,事情看起来好多了。


public class Old{
    protected Old old;
    protected List stuff;

    //Needed for JUnit
    public Old(){
    }

    //Here's my new copy constructor.
    public Old(Old old){
        this.stuff=new ArrayList(old.getStuff());
        this.old=null;
    }

    public Old(List stuff){
        this.stuff=stuff;
        old=new Old(this);//Here I now call the copy constructor.
    }

    public void add(){
        stuff.add(2);
    }

    public void match(){
        System.out.printf("old:%d\nnew:%d\n",old.getStuff().size(),stuff.size());
    }

    public List getStuff(){
        return new ArrayList(stuff);
    }

    @Test
    public void testOld(){
        List list=new ArrayList();
        list.add(1);
        Old thing=new Old(list);
        thing.add();
        thing.match();
    }
}

输出:

old:1
new:2

答案 5 :(得分:0)

跟踪列表的更改可以使用ChangeTrackingUniqueList完成 - 它提供了诸如“list.isChanged()”,“list.getDeleted()”,“list.getAdded()”之类的方法,你甚至可以使用“list.revert()”恢复列表。但它没有检测到列表中对象的更改。它仅通过添加,删除或替换对象来检测列表本身是否已更改。