7.
Aspetti avanzati7.1 Copia e uguaglianza
La semantica di default per le operazioni di assegnamento e di confronto per = fra oggetti prevede che vengano coinvolte solo le identità degli oggetti (in pratica, spesso, dei puntatori di memoria). Nel caso dell'assegnamento questo pu creare degli spiacevoli effetti collaterali dovuti alla condivisione di strutture dinamiche che si viene a creare. Per evitarli occorre effettuare l'assegnamento con operazioni del tipo
a:=copia(b) che ha l'effetto di creare in a un puntatore ad una copia dell'oggetto indicato in b.7.2 Asserzioni
Le asserzioni in un linguaggio di programmazione sono delle espressioni booleane valutabili a tempo di esecuzione che possono assolvere a diversi scopi:
·
forma primitiva di specifica e di documentazione·
prevenzione contro possibili malfunzionamenti del software; in particolare nella OOP come precondizioni e postcondizioni dei metodi·
strumento di verifica durante la fase di testing·
possibili clausole di uno stile di programmazione noto come progetto per contratto[Meyer97]I linguaggi OOP si differenziano notevolmente rispetto al supporto e alla varietà di tipi di asserzioni che mettono a disposizione del programmatore.
7.3 Eccezioni
Per aumentare la robustezza di un'applicazione, tutti i pi recenti linguaggi OOP mettono a disposizione la possibilità definire, sollevare e trattare eccezioni, ciò eventi causati da malfunzionamenti o imprevisti hardware o software che si possono sempre verificare. In particolare il programmatore di ogni metodo ha la possibilità di catturare un'eccezione, riconoscerla e prendere le necessarie azioni di recupero almeno per mantenere l'oggetto in uno stato interno consistente. Il trattamento standard di default quello di propagare l'eccezione al chiamante, fino eventualmente a raggiungere il metodo avviato per primo, facendolo abortire.
7.4 Contenitori e iteratori
Una volta definito come classe un contenitore astratto di dati (ad es. una pila, una lista, una tabella, ecc.) si può presentare il problema di attraversare uno di questi contenitori, ciò di costruire cicli del tipo
portati sul primo elemento
finch non sei giunto all'ultimo e non hai trovato una
condizione di arresto
elabora l'elemento corrente
passa all'elemento successivo
finefinch
La soluzione pi generale, flessibile e astratta a questo problema prevede il ricorso a degli oggetti chiamati iteratori la cui classe di appartenenza viene definita in "simbiosi" a quella dei contenitori che li attraversano. In pratica essi assolvono ad un ruolo molto simile a quello rivestito dagli indici dei "for" per l'attraversamento degli array. La differenza che viene completamente nascosta la rappresentazione dei cursori. Il cursore l'oggetto che all'interno di un iteratore "punta" all'elemento del contenitore in corso di attraversamento. Questo permette un domani di cambiare sia la rappresentazione dei contenitori che quella degli iteratori senza cambiare il codice delle applicazioni "clienti".
7.5 Distruttori
Oltre ai costruttori può essere talvolta necessario che il programmatore definisca dei metodi, chiamati spesso distruttori, che assolvono al compito di svolgere delle azioni finali prima che l'oggetto venga completamente distrutto e le sue aree di memoria rese disponibili per operazioni di allocazione di nuovi oggetti. In particolare, in C++, i distruttori hanno spesso l'onere di recuperare parte della memoria occupata dall'oggetto. Da questo onere sono liberi tutti i linguaggi che prevedono il garbage collector, ciò quel processo della macchina virtuale del linguaggio che assolve appunto al compito di individuare e recuperare le aree occupate da oggetti che si rendono inaccessibili ("garbage", appunto).
7.6 Persistenza
La persistenza nella OOP la proprietà di un oggetto di sopravvivere al processo che l'ha creato. Un modo per implementare la persistenza tipicamente quello di "salvarlo" su un supporto di memoria persistente, come il disco. I linguaggi OOP adottano varie tecniche per fornire questo tipo di servizio all'utenza. Il pi semplice e primitivo quello di mettere a disposizione delle primitive di salvataggio e recupero di un oggetti su un file con un certo nome. Il pi sofisticato (ma anche il pi semplice da usarsi) quello di prevedere la possibilitàdi dichiarare come persistenti alcune classi: gli oggetti creati saranno automaticamente resi persistenti .
7.7 Covarianza
Una questione che si può porre nel progetto delle classi : si pu, al
momento di ridefinire un metodo (overriding), cambiare il tipo di un parametro
formale ? in particolare: si può specificare un sottotipo ?
I linguaggi si dividono sostanzialmente in due categorie: quelli che rispondono
negativamente (linguaggi non-varianti, come C++ e Java) e quelli che
rispondono affermativamente (linguaggi covarianti, come Eiffel).
Purtroppo la covarianza del sistema di tipi, pur venendo incontro a utili
esigenze pratiche di flessibilità, espone il linguaggio ad alcuni rischi.
7.8 Concorrenza e reti
Fin dal suo concepimento, nel paradigma ad oggetti stato preso in considerazione l'ipotesi di considerare ogni oggetto come avente un proprio "thread of control". In particolare, Smalltalk vedeva la chiamata di un metodo come la spedizione di un messaggio da parte di un oggetto mittente (sender) ad uno ricevente (receiver) contenente la richiesta di un particolare servizio il cui termine veniva comunicato al mittente assieme all'eventuale restituzione di un valore. Con una visione pi moderna, si può considerare la chiamata di un metodo come la richiesta di un servizio ad un oggetto servente in grado di accettare e ordinare opportunamente le richieste provenienti dai vari oggetti clienti. Alcuni linguaggi ad oggetti mettono a disposizione strumenti od estensioni a supporto della concorrenza e/o della distribuzione degli oggetti. Ad esempio Java mette a disposizione la libreria RMI (Remote Method Invocation) per la chiamate di metodi ad oggetti remoti.