Le clonage est un paradigme de programmation de base. Le fait que Java l'ait mal implémenté à bien des égards ne diminue en rien le besoin de clonage. Et, il est facile de mettre en œuvre le clonage qui fonctionnera comme vous le souhaitez, peu profond, profond, mixte, peu importe. Vous pouvez même utiliser le nom clone pour la fonction et ne pas implémenter Cloneable si vous le souhaitez.
Supposons que j'ai des classes A, B et C, où B et C sont dérivés de A. Si j'ai une liste d'objets de type A comme ceci:
ArrayList<A> list1;
Maintenant, cette liste peut contenir des objets de type A, B ou C. Vous ne savez pas de quel type sont les objets. Donc, vous ne pouvez pas copier la liste comme ceci:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(new A(a));
}
Si l'objet est en fait de type B ou C, vous n'obtiendrez pas la bonne copie. Et si A était abstrait? Maintenant, certaines personnes ont suggéré ceci:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
if(a instanceof A) {
list2.add(new A(a));
} else if(a instanceof B) {
list2.add(new B(a));
} else if(a instanceof C) {
list2.add(new C(a));
}
}
C'est une très, très mauvaise idée. Que faire si vous ajoutez un nouveau type dérivé? Que faire si B ou C sont dans un autre package et que vous n'y avez pas accès dans cette classe?
Voici ce que vous aimeriez faire:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(a.clone());
}
De nombreuses personnes ont expliqué pourquoi l'implémentation Java de base du clone était problématique. Mais, il est facilement surmonté de cette façon:
En classe A:
public A clone() {
return new A(this);
}
En classe B:
@Override
public B clone() {
return new B(this);
}
En classe C:
@Override
public C clone() {
return new C(this):
}
Je n'implémente pas Cloneable, en utilisant simplement le même nom de fonction. Si vous n'aimez pas ça, donnez-lui un autre nom.