Questa domanda sarà un po 'lunga. Per favore, sopportami.
Qualcosa che è accaduto in un mio progetto mi ha fatto pensare a come copiare in sicurezza gli oggetti. Presenterò la situazione che ho avuto e poi fare una domanda.
C'era una classe SomeClass
:
class SomeClass {
private Thing[] things;
public SomeClass(Thing[] things){
this.things = things;
}
// irrelevant stuff omitted
public SomeClass copy(){
return new SomeClass(things);
}
}
C'era un'altra classe Processor
che prende SomeClass
oggetti, li copia (tramite someClassInstance.copy()
), manipola lo stato della copia e restituisce la copia. Eccolo:
class Processor{
public SomeClass processObject(SomeClass object){
SomeClass copy = object.copy();
manipulateTheCopy(copy);
return copy;
}
// irrelevant stuff omitted
}
Ho eseguito questo, e aveva dei bug. Ho esaminato questi bug e ho scoperto che le manipolazioni Processor
su copy
riguardano effettivamente non solo la copia, ma anche l'originale SomeClass
oggetto passato in processObject
.
Ho scoperto che era perché l'originale e lo stato di copia condivisa - perché l'originale ha passato il suo campo things
nella copia durante la sua creazione.
Questo mi ha fatto capire che copiare oggetti è più difficile che istanziarli con gli stessi campi dell'originale.
Affinché i due oggetti siano completamente disconnessi, senza nessuno stato condiviso, anche ciascuno dei campi passati alla copia deve essere copiato. E se quell'oggetto contiene altri oggetti, anche questi devono essere copiati. E così via.
Quindi, in pratica, per poter effettivamente copiare un oggetto, ogni classe nel sistema deve avere un metodo copy()
, che richiama anche copy()
su tutti i suoi campi, e così via .
Quindi, per esempio, per copy()
in SomeClass funzionare, deve assomigliare a questo:
public SomeClass copy() {
Thing[] copyThings = new Thing[things.length];
for(int i = 0; i < things.length; i++)
copyThings[i] = things[i].copy();
return new SomeClass(copyThings);
}
E se Thing
ha i propri campi oggetto, il suo metodo copy()
deve essere appropriato:
class Thing {
private Apple apple;
private Pencil pencil;
private int number;
public Thing(Apple apple, Pencil pencil, int number){
this.apple = apple;
this.pencil = pencil;
this.number = number;
}
public Thing copy(){
// 'number' is a primitve.
return new Thing(apple.getCopy(), pencil.getCopy(), number);
}
}
E così via.
Ovviamente, invece di tutte le classi che hanno un metodo copy()
, il meccanismo di copia può accadere in tutti i getter e i costruttori di classi (a meno che non siano posti dove non è adatto, per esempio quando il campo punta a un oggetto esterno, non a un oggetto che 'fa parte' di questo oggetto).
Tuttavia, ciò significa che per poter copiare in modo sicuro un oggetto, la maggior parte delle classi dovrebbe avere meccanismi di copia nei loro getter.
La mia domanda è divisa in due parti:
-
Con quale frequenza hai bisogno di ottenere una copia di un oggetto? Si tratta di un problema normale?
-
La tecnica descritta è comune e / o ragionevole? O c'è un modo migliore per fare copie sicure degli oggetti?