Quasi tutti i linguaggi di programmazione orientati agli oggetti forniscono un modo per copiare oggetti. Poiché la maggior parte delle lingue non fornisce la maggior parte degli oggetti per i programmi, un programmatore deve definire come un oggetto deve essere copiato, così come deve definire se due oggetti sono identici o addirittura comparabili in primo luogo. Molte lingue forniscono un comportamento predefinito.
Come viene risolta la copia varia da lingua a lingua e quale concetto di un oggetto ha.
Copia lazyEdit
Una copia lazy è un’implementazione di una copia deep., Quando si copia inizialmente un oggetto, viene utilizzata una copia superficiale (veloce). Un contatore viene anche utilizzato per tenere traccia di quanti oggetti condividono i dati. Quando il programma desidera modificare un oggetto, può determinare se i dati sono condivisi (esaminando il contatore) e può eseguire una copia approfondita se necessario.
Lazy copy guarda all’esterno come una copia profonda, ma sfrutta la velocità di una copia superficiale quando possibile. Il rovescio della medaglia sono piuttosto elevati, ma i costi di base costanti a causa del contatore. Inoltre, in determinate situazioni, i riferimenti circolari possono causare problemi.
La copia pigra è correlata alla copia su scrittura.,
In JavaEdit
Quanto segue presenta esempi per uno dei linguaggi orientati agli oggetti più utilizzati, Java, che dovrebbe coprire quasi tutti i modi in cui un linguaggio orientato agli oggetti può trattare questo problema.
A differenza di C++, gli oggetti in Java sono sempre accessibili indirettamente tramite riferimenti. Gli oggetti non vengono mai creati implicitamente ma vengono sempre passati o assegnati da una variabile di riferimento. (I metodi in Java sono sempre passati per valore, tuttavia, è il valore della variabile di riferimento che viene passata.,) La macchina virtuale Java gestisce la garbage collection in modo che gli oggetti vengano ripuliti dopo che non sono più raggiungibili. Non esiste un modo automatico per copiare un determinato oggetto in Java.
La copia viene solitamente eseguita da un metodo clone () di una classe. Questo metodo di solito, a sua volta, chiama il metodo clone() della sua classe padre per ottenere una copia e quindi esegue qualsiasi procedura di copia personalizzata., Alla fine questo arriva al metodo clone() di Object
(la classe più alta), che crea una nuova istanza della stessa classe dell’oggetto e copia tutti i campi nella nuova istanza (una “copia superficiale”). Se viene utilizzato questo metodo, la classe deve implementare l’interfaccia marcatoreCloneable
, altrimenti genererà un’eccezione CloneNotSupportedException. Dopo aver ottenuto una copia dalla classe genitore, il metodo clone() di una classe può quindi fornire funzionalità di clonazione personalizzate, come la copia profonda (cioè, duplicare alcune delle strutture a cui fa riferimento l’oggetto) o dare alla nuova istanza un nuovo ID univoco.
Il tipo di ritorno di clone() èObject
, ma gli implementatori di un metodo clone potrebbero scrivere il tipo dell’oggetto clonato invece a causa del supporto di Java per i tipi di ritorno covarianti. Un vantaggio dell’uso di clone() è che poiché è un metodo sovrascrivibile, possiamo chiamare clone() su qualsiasi oggetto e utilizzerà il metodo clone() della sua classe, senza che il codice chiamante debba sapere quale sia quella classe (che sarebbe necessaria con un costruttore di copia).,
Uno svantaggio è che spesso non si può accedere al metodo clone() su un tipo astratto. La maggior parte delle interfacce e delle classi astratte in Java non specifica un metodo public clone (). Pertanto, spesso l’unico modo per utilizzare il metodo clone() è se la classe di un oggetto è nota, il che è contrario al principio di astrazione dell’uso del tipo più generico possibile. Ad esempio, se si dispone di un riferimento Elenco in Java, non è possibile richiamare clone() su tale riferimento perché List non specifica alcun metodo clone() pubblico., Le implementazioni di List come ArrayList e LinkedList hanno generalmente metodi clone (), ma è un’astrazione scomoda e cattiva portare in giro il tipo di classe di un oggetto.
Un altro modo per copiare oggetti in Java è serializzarli tramite l’interfaccia Serializable
. Questo è in genere utilizzato per scopi di persistenza e protocollo di filo, ma crea copie di oggetti e, a differenza del clone, una copia profonda che gestisce con grazia grafici ciclati di oggetti è prontamente disponibile con il minimo sforzo da un programmatore.,
Entrambi questi metodi soffrono di un problema notevole: il costruttore non viene utilizzato per gli oggetti copiati con clone o serializzazione. Ciò può portare a bug con dati inizializzati in modo improprio, impedisce l’uso di final
campi membro e rende la manutenzione difficile. Alcune utility tentano di superare questi problemi utilizzando reflection per copiare oggetti profondi, come la libreria di clonazione profonda.,
In EiffelEdit
Gli oggetti Runtime in Eiffel sono accessibili indirettamente tramite riferimenti o come oggetti espansi i cui campi sono incorporati all’interno degli oggetti che li utilizzano. Cioè, i campi di un oggetto sono memorizzati esternamente o internamente.
La classe EiffelANY
contiene funzionalità per la copia superficiale e profonda e la clonazione di oggetti. Tutte le classi Eiffel ereditano da ANY
, quindi queste funzionalità sono disponibili in tutte le classi e sono applicabili sia agli oggetti di riferimento che a quelli espansi.,
La funzionecopy
effettua una copia superficiale campo per campo da un oggetto all’altro. In questo caso non viene creato alcun nuovo oggetto. Se y
sono stati copiati x
, quindi gli stessi oggetti a cui fa riferimento y
prima di copy
, sarà anche riferimento x
dopo il copy
completa di funzionalità.,
Per effettuare la creazione di un nuovo oggetto che è un duplicato superficiale di y
, viene utilizzata la funzione twin
. In questo caso, viene creato un nuovo oggetto con i suoi campi identici a quelli della sorgente.
La funzionetwin
si basa sulla funzionecopy
, che può essere ridefinita in discendenti diANY
, se necessario. Il risultato di twin
è del tipo ancoratolike Current
.,
La copia profonda e la creazione di gemelli profondi possono essere eseguite utilizzando le funzionalitàdeep_copy
edeep_twin
, ereditate nuovamente dalla classeANY
. Queste caratteristiche hanno il potenziale per creare molti nuovi oggetti, perché duplicano tutti gli oggetti in un’intera struttura oggetto. Poiché vengono creati nuovi oggetti duplicati invece di copiare semplicemente i riferimenti a oggetti esistenti, le operazioni profonde diventeranno una fonte di problemi di prestazioni più facilmente delle operazioni superficiali.,
In altre lingueedit
In c#, anziché utilizzare l’interfacciaICloneable
, è possibile utilizzare un metodo di estensione generico per creare una copia profonda utilizzando reflection. Questo ha due vantaggi: In primo luogo, fornisce la flessibilità di copiare ogni oggetto senza dover specificare ogni proprietà e variabile da copiare manualmente. In secondo luogo, poiché il tipo è generico, il compilatore garantisce che l’oggetto di destinazione e l’oggetto di origine abbiano lo stesso tipo.,
In Objective-C, i metodicopy
emutableCopy
sono ereditati da tutti gli oggetti e destinati all’esecuzione di copie; quest’ultimo è per la creazione di un tipo mutabile dell’oggetto originale. Questi metodi a loro volta chiamano i metodi copyWithZone
e mutableCopyWithZone
, rispettivamente, per eseguire la copia. Un oggetto deve implementare il metodo copyWithZone
corrispondente per essere copiabile.
In OCaml, la funzione di libreria Oo.copia esegue una copia superficiale di un oggetto.,
In Ruby, tutti gli oggetti ereditano due metodi per eseguire copie poco profonde, clone e dup. I due metodi differiscono in quantoclone
copia lo stato contaminato di un oggetto, lo stato congelato e tutti i metodi singleton che può avere, mentredup
copia solo il suo stato contaminato. Le copie profonde possono essere ottenute scaricando e caricando il flusso di byte di un oggetto o la serializzazione YAML. In alternativa, è possibile utilizzare la gemma deep_dive per eseguire una copia profonda controllata dei grafici degli oggetti.,
In Perl, le strutture nidificate vengono memorizzate mediante l’uso di riferimenti, quindi uno sviluppatore può eseguire il loop sull’intera struttura e ri-fare riferimento ai dati o utilizzare la funzionedclone()
dal modulo Memorizzabile.
In VBA, un’assegnazione di variabili di tipo Object
è una copia superficiale, un’assegnazione per tutti gli altri tipi (tipi numerici, Stringa, tipi definiti dall’utente, array) è una copia profonda. Quindi la parola chiave Set
per un’assegnazione segnala una copia superficiale e la parola chiave (opzionale)Let
segnala una copia profonda., Non esiste un metodo integrato per le copie profonde degli oggetti in VBA.
Lascia un commento