2011-01-26 159 views
3

我正在研究一些代碼,當對象中的某些內容發生變化時,我想檢測這些代碼。跟蹤更改的最簡單方法之一是保留對象的舊副本。但是,看起來像獲取深圖的副本可能很困難。下面是我的嘗試:如何跟蹤對象圖的更改?

 

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不創建一個深拷貝。我真正想要的是跟蹤對該列表的更改以及潛在的對象圖。什麼是其他一些簡單的選擇?

+0

要跟蹤列表的變化,您可以使用此開源庫: http://www.fuin.org/utils4j/examples/track-list-changes.html – user1672934

回答

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 
2

根據您的具體要求是什麼,這可能努力改變對象制定者

  1. 控制訪問(即使用適當的封裝)
  2. 添加修改陣列是字符串
  3. 數組每次調用setter或其他任何改變對象的方法,調用toString並存儲結果

這很簡單,但可能適合您的需求並具有以下優點:

  1. 您可以將它抽象爲基類以供重用。
  2. 您可以測試字符串相等性,以便不記錄不會更改任何內容的集合。 (將當前更改與修訂數組中的最後一個元素進行比較)
  3. 您可能會非常喜歡並擁有'recordChanges'之類的屬性,因此錄製僅在true時發生(可能是默認設置)。通過這種方式,如果您要連續執行一組設置,則可以一次記錄所有更改,而不是每個設置。 (即創建的startRecording和stopRecording方法,當你的startRecording記錄當前的狀態)

它具有以下額外的工作:

  1. 你將不得不實行了堅實的toString和hashCode雖然。無論如何你可能必須這樣做

  2. 如果你連續調用一組套件,它可能會很慢,但是你可以用上面的建議3來緩解。

最後,如果你有真正看中的,你可以實現的四個Momento pattern的團伙。對於你需要的東西(因爲它可以讓你恢復到以前的狀態),這可能是過度殺傷的,但仍然會很棒。

0

您正在比較ArrayList和相同ArrayList的副本而沒有任何更改。無論副本是否很深,它們總是具有相同數量的元素。

是的,在這種情況下,ArrayList保存引用,如果您在ArrayList的構造函數中傳遞一個列表,它將不會創建新對象,而是它將具有與對象相同的引用。

0

您可以考慮使用Observer。您可以創建一個Observer類,在發生更改時由您的對象通知您。也許你可以保留舊的和新的價值。然後,您可以將觀察者添加到要跟蹤的每個對象。你可以閱讀更多關於這個選項herehere

0

您只將指針複製到引用。 list和old.stuff都指向同一個對象。對列表所做的任何更改都會反映在old.stuff中,反之亦然。您想使用Collections.copy製作列表的副本。然後,對列表的任何更改都不會反映在old.stuff中的參考(對差異列表對象)中。有關更多詳細信息,請參閱this answer

0

列表的跟蹤變化可以用ChangeTrackingUniqueList做 - 它提供了像 「list.isChanged()」 方法, 「list.getDeleted()」,「清單.getAdded()「,你甚至可以用」list.revert()「來恢復列表。但它不會檢測列表中對象的更改。它僅檢測列表本身是否通過添加,刪除或替換對象而更改。