2012-11-15 20 views
5

Nagle napotkałem problem z wykonaniem głębokiej polimorficznej kopii w Javie. Implementacja Clonable rozwiązuje problem w moim przypadku, ale często jest określana jako "zła" technika.Polimorficzna kopia w Javie

Tak, oto moje próby znalezienia "no-Clonable" rozwiązanie:

public class Parent { 
    int x; 

    public Parent() {} 

    public Parent(int x0) { 
     x = x0; 
    } 

    public Parent copy() { 
     Parent b = new Parent(); 
     b.assign(this); 

     return b; 
    } 

    protected void assign(Parent c) { 
     x = c.x; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x; 
    } 
} 

public class Child extends Parent { 
    int y; 

    protected Child() {} 

    public Child(int x0, int y0) { 
     super(x0); 
     y = y0; 
    } 

    @Override 
    public Child copy() { 
     Child b = new Child(); 
     b.assign(this); 

     return b; 
    } 

    @Override 
    protected void assign(Child c) { 
     super.assign(c); 
     y = c.y; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x + "," + y; 
    } 
} 

public class Test { 
    public static void main(String[] args) { 
     Parent x = new Parent(5); 
     Child y = new Child(10, 20); 
     Parent z = x.copy(); 
     Parent w = y.copy(); 

     System.out.println(x); 
     System.out.println(y); 
     System.out.println(z); 
     System.out.println(w); 
    } 
} 

wyjście jest:

com.xxx.zzz.Parent, 5 
com.xxx.zzz.Child, 10,20 
com.xxx.zzz.Parent, 5 
com.xxx.zzz.Child, 10,20 

a inny (krótszy) sposób robi to samo (z wykorzystaniem Odbicie):

public class Parent { 
    int x; 

    public Parent() {} 

    public Parent(int x0) { 
     x = x0; 
    } 

    public Parent copy() { 
     try { 
      Parent b = getClass().newInstance(); 
      b.assign(this); 
      return b; 
     } catch (InstantiationException | IllegalAccessException e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 

    protected void assign(Parent c) { 
     x = c.x; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x; 
    } 
} 

public class Child extends Parent { 
    int y; 

    protected Child() {} 

    public Child(int x0, int y0) { 
     super(x0); 
     y = y0; 
    } 

    protected void assign(Child c) { 
     super.assign(c); 
     y = c.y; 
    } 

    @Override 
    public String toString() { 
     return getClass().getName() + ", " + x + "," + y; 
    } 
} 

Nie ma potrzeby nadpisywania kopii() w klasie Dziecko. Ale nie jestem pewien, jak "legalne" jest użycie getClass(). NewInstance() do skonstruowania placeholder kopii ...

Czy powyższe rozwiązania warte są użycia czy są bardziej powszechne/solidne/proste podejścia?

Dziękujemy!

+0

To nie działa, jeśli 'Dziecko' ma domyślny konstruktor. –

Odpowiedz

2

Twoje rozwiązanie wygląda w porządku dla mnie, dla tego konkretnego przypadku użycia.

Głównymi ograniczeniami korzystania newInstance(), są następujące:

  • działa tylko z obiektami, które mają nie-Arg konstruktora i
  • byłoby w stanie klonować obiekty, które mają końcowe pola

Istnieje kilka bibliotek, które obsługują klonowanie. Spójrz na Kryo. Jest to biblioteka do serializacji, która obsługuje również klonowanie (głębokie i płytkie), w tym obiekty bez konstruktorów bez-arg, lub które mają końcowe pola.

0

Nigdy nie byłem wielkim fanem podejścia "clone()". konstruktorzy Kopiowanie wydają się być bardziej elegancki IMO:

public class Parent { 
    int x; 

    public Parent() { 
     super(); 
    } 

    public Parent(Parent other) { 
     super(); 
     this.x = other.x; 
    } 
} 

public class Child extends Parent { 
    int y; 

    public Child() { 
     super(); 
    } 

    public Child(Child other) { 
     super(other); 
     this.y = other.y; 
    } 
} 

Uwaga ta ma także dodatkową zaletę, że są w stanie to zrobić, jeśli chcesz:

Parent p = new Parent(new Child(...)); 

Można oczywiście zapobiec tego zachowania w konstruktor sprawdzając konkretny typ klasy argumentu , ale nie widzę powodu, dla którego musiałbyś w większości przypadków.

+1

Problem polega na tym, że konstruktorzy kopii nie radzą sobie prawidłowo z polimorfizmem – user671786