Zapis zmian

0

Napisałem klasę której celem jest przechowywanie historii zmian w pewnym obiekcie. Chodziło o funkcje Undo i Redo. Moja klasa działa świetnie z prostą zmienną int niestety z obiektami klasy przechowującej dane już nie działa. Po debugowaniu okazało się że każdy zapisany obiekt jest jakby referencją do do obiektu który chciałem skopiować choć teoretycznie ze zmienną typu int czy String działało. Dlaczego z bardziej złożonymi obiektami nie chce działać ?
Poniżej podaje moje klasy.

Klasa odpowiedzialna za przechowywanie zmian

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bibtexdescriptor;

/**
 *
 * @author Kaa
 */
public class ChangeManager<K> {
    int size = 0;
    Node<K> root;
    Node<K> current;
    int maxsize;

    public ChangeManager(K item) {
        size++;
        root = new Node<>(null, null, item);
        current = root;
    }
    public ChangeManager(K item, int maxsize) {
        size++;
        root = new Node<>(null, null, item);
        current = root;
        this.maxsize = maxsize+1;
    }
    
    public void addChange(K item){
        size++;
        Node<K> tep  = current;
        current = new Node<>(tep, null, item);
        tep.nastepny = current;
        if(maxsize>1 &&maxsize<size){
            root = root.nastepny;
            root.poprzedni = null;
            System.gc();
        }
    }

    public void setMaxsize(int maxsize) {
        this.maxsize = maxsize+1;
    }
    
    
    
    public boolean canUndo(){
        if(current.poprzedni!=null)return true;
        return false;
    }
    
        public boolean canRedo(){
        if(current.nastepny!=null)return true;
        return false;
    }
        
    public K undo(){
        if(canUndo()){
            size--;
            current = current.poprzedni;
            return current.obiekt;
        }else{
            throw new UnsupportedOperationException("Nothing to undo");
        }
    }
    public K redo(){
        if(canRedo()){
            size++;
            current = current.nastepny;
            return current.obiekt;
        }else{
            throw new UnsupportedOperationException("Nothing to redo");
        }
    }
    public int getSize(){
        return size;
    }
    
    public void trimToSize(int trim) {
        if (trim < size) {
            for (int i = 0; i < size - trim; i++) {
                root = root.nastepny;
                root.poprzedni = null;
                System.gc();
            }
        }
    }
    private class Node<K>{
        Node<K> poprzedni;
        Node<K> nastepny;
        K obiekt;

        public Node(Node<K> poprzedni, Node<K> nastepny, K obiekt) {
            this.poprzedni = poprzedni;
            this.nastepny = nastepny;
            this.obiekt = obiekt;
        }
    }
}

Klasa której obiekty chcę przechowywać

class DataContainer implements Serializable{
    
    private PublicationType type;
    private HashMap<Enum, String> fields;
    private HashMap<Enum, String> oFields;
    private HashMap<String, String> userFields;
    private String name;

    public DataContainer(PublicationType type, HashMap<Enum, String> fields, HashMap<Enum, String> oFields, HashMap<String, String> userFields, String name) {
        this.type = type;
        this.fields = fields;
        this.oFields = oFields;
        this.userFields = userFields;
        this.name = name;
    }

    public PublicationType getType() {
        return type;
    }

    public HashMap<Enum, String> getFields() {
        return fields;
    }

    public HashMap<Enum, String> getoFields() {
        return oFields;
    }

    public HashMap<String, String> getUserFields() {
        return userFields;
    }

    public String getName() {
        return name;
    }
}
0

Już tłumaczę na czym polega problem: inty nie działają jak klasy.

Dla zobrazowania przykład.

Z intami:

public class inty {
    public static void main(String[] args) {
    	int a = 1;
    	int b = 2;
    	a = b; // do zmiennej a przypisuję WARTOŚĆ zmiennej b
    	b = 3; // do zmiennej b przypisuję wartość 3    	
    	System.out.println(a); // 2 
    	System.out.println (b); // 3
    }
}

Z klasami:

class klasa {
	int x;
	
	klasa(int x) {
		this.x = x;
	}
	
	int get() {
		return x;
	}
	
	void set(int x) {
		this.x = x;
	}
}

public class klasy {
    public static void main(String[] args) {
    	klasa a = new klasa(1);
    	klasa b = new klasa(2);
    	a = b; // do zmiennej a przypisuję REFERENCJĘ (a nie wartość) zmiennej b
    	b.set(3); // do zmiennej b przypisuję wartość 3    	
    	System.out.println(a.get()); // 3 a nie 2 
    	System.out.println (b.get()); // 3
    }
}

Niby jest to samo (tylko zamiast intów klasy), ale wynik inny. Dlaczego? Bo przypisała się referencja (tak jakby adres w pamięci, a nie kopia danych). Może to trochę dezorientujące, ale skąd kompilator ma wiedzieć jak skopiować dane z twojej własnej klasy (może to też ze względów bezpieczeństwa, żeby nie robić prosto kopii dużych danych - tak jak nie da się przekazać tablic do funkcji w C tylko przez wskaźniki)?

Typy prymitywne (np. int, double) kopiują. A klasy (np. twoja klasa, albo String - dlatego przy porównywaniu trzeba użyć metody equals zamiast ==, które porówna tylko referencję a nie zawartość Stringa) działają na referencjach.

Jest jednak rozwiązanie. Musisz sam zrobić metodę która skopiuje dane - czyli konstruktor kopiujący (lub przy porównywaniu - własna metoda porównywająca) - tzn. konstruktor z takim samym typem parametru jak klasa.
Tu rozwiązanie dla mojego przykładu:

class klasa {
	int x;
	
	klasa(int x) {
		this.x = x;
	}
	
	klasa(klasa k) {
		this.x = k.x;
	}
	
	int get() {
		return x;
	}
	
	void set(int x) {
		this.x = x;
	}
}

public class klasy2 {
    public static void main(String[] args) {
    	klasa a = new klasa(1);
    	klasa b = new klasa(2);
    	a = new klasa(b); // do zmiennej a przypisuję kopię b (teraz jest jak w intach)
    	b.set(3); // do zmiennej b przypisuję wartość 3    	
    	System.out.println(a.get()); // 2 jak w intach
    	System.out.println (b.get()); // 3
    }
}
0

Poczytaj sobie o wzorcu projektowym memento.

1 użytkowników online, w tym zalogowanych: 0, gości: 1