Anteprima
Vedrai una selezione di 10 pagine su 170
Appunti completi di Ingegneria del software Pag. 1 Appunti completi di Ingegneria del software Pag. 2
Anteprima di 10 pagg. su 170.
Scarica il documento per vederlo tutto.
Appunti completi di Ingegneria del software Pag. 6
Anteprima di 10 pagg. su 170.
Scarica il documento per vederlo tutto.
Appunti completi di Ingegneria del software Pag. 11
Anteprima di 10 pagg. su 170.
Scarica il documento per vederlo tutto.
Appunti completi di Ingegneria del software Pag. 16
Anteprima di 10 pagg. su 170.
Scarica il documento per vederlo tutto.
Appunti completi di Ingegneria del software Pag. 21
Anteprima di 10 pagg. su 170.
Scarica il documento per vederlo tutto.
Appunti completi di Ingegneria del software Pag. 26
Anteprima di 10 pagg. su 170.
Scarica il documento per vederlo tutto.
Appunti completi di Ingegneria del software Pag. 31
Anteprima di 10 pagg. su 170.
Scarica il documento per vederlo tutto.
Appunti completi di Ingegneria del software Pag. 36
Anteprima di 10 pagg. su 170.
Scarica il documento per vederlo tutto.
Appunti completi di Ingegneria del software Pag. 41
1 su 170
D/illustrazione/soddisfatti o rimborsati
Disdici quando
vuoi
Acquista con carta
o PayPal
Scarica i documenti
tutte le volte che vuoi
Estratto del documento

Problemi legati all'overriding

Alcuni problemi possono essere legati all'overriding: se si ha fatto override di un metodo di A in B1 e B2, quale versione si ha in C?

Tutti i problemi presentati sono legati alla semantica.

La soluzione all'ereditarietà multipla

Java supporta l'ereditarietà multipla di interfaccia, ma solo l'interfaccia singola di implementazione.

Ritornando all'ereditarietà singola...

Correttezza e robustezza

Due aspetti da prendere in considerazione legati alle classi sono:

Correttezza: quanto un codice è stabile, privo di errori

Robustezza: quanto la classe è in grado di reggere successive evoluzioni nelle classi figlie per poter essere sostituibile e continui a mantenere la sua correttezza

La correttezza è un problema statico, ovvero quali sono le modalità di implementazione che consentono ad una classe di comportarsi in modo corretto.

La robustezza è una questione dinamica, ovvero come implementare una classe in modo da...

consentirle di tollerare l'evoluzione e le successive versioni delle sue superclassi e sottoclassi.

Il problema della classe base fragile (FBC)

Come si può far evolvere una classe senza che questo provochi problemi di funzionamento alle sue sottoclassi?

La stretta dipendenza fra una classe base e sottoclassi sviluppate in contesti indipendenti viene chiamata problema della classe base fragile.

Questo problema possiede due aspetti, uno legato alla sintassi (interfacce) e uno legato alle implementazioni: si parla di FBC sintattico e FBC semantico.

Il problema della classe base fragile sintattico

L'idea è che una classe non dovrebbe richiedere una ricompilazione solo a causa di cambiamenti sintattici all'interfaccia delle sue superclassi.

Java consente di compilare solo le classi che sono cambiate, senza dover ricompilare l'intero progetto, mentre in C++ si è costretti a ricompilare l'applicazione. È possibile quindi inserire solo le classi che

è che se si cambia l'ordine dei metodi nella VMT, la classe derivata salta ad una posizione sbagliata. Questo problema è noto come "classe base fragile sintattico". Una soluzione a questo problema è quella di utilizzare le tabelle di dispatch dei metodi (virtual method tables) durante il caricamento delle applicazioni anziché a tempo di compilazione. Questa è la soluzione adottata da Java, che non soffre del problema della classe base fragile sintattico.

L'aspetto semantico è legato al fatto di come una classe può rimanere valida in presenza di cambiamenti dell'implementazione di una superclasse. Il problema è che i metodi di una sottoclasse hanno un accesso completo alla parte di stato ereditato dalle superclassi e ai metodi non pubblici, quindi possono operare su dettagli implementativi che potrebbero cambiare in una versione successiva della superclasse. Si ha una rottura dell'incapsulamento, in quanto è possibile accedere a quello che succede nella classe padre dentro alla classe figlia, operando in qualcosa che se cambiato può dare problemi.

Soluzione parziale al FBC semantico

La soluzione è quella di introdurre un'interfaccia di specializzazione, oltre alla classica interfaccia d'uso: è l'insieme dei campi e dei metodi marcati come protected nelle classi Java ed è pensata per la derivazione di sottoclassi. Si ha quindi un incapsulamento a tre

livelli:

  • private: accessibile solo ai metodi di una classe
  • protected: accessibile anche alle sottoclassi
  • public: accessibile a tutti

Trattandosi di una questione semantica, l'introduzione dell'interfaccia protected non risolve però completamente il problema.

Esempio di un problema semantico

Si ha una classe che stampa un documento ma senza stampare il numero della pagina. Si crea quindi una sottoclasse che ridefinisce il metodo di stampa aggiungendo il numero della pagina, ma dato che l'array di pagine parte da zero bisogna sommare sempre 1, per avere il numero di pagina corretto.

Se l'autore della classe padre decide di modificare l'implementazione in modo che il numero della pagina diventa effettivamente quello corretto, si ha che la classe figlia stampa il numero di pagina+1, che non è corretto.

Si ha quindi che l'ereditarietà è un meccanismo troppo fragile: la soluzione più nota è quella basata sul meccanismo di

composizione fra oggetti.

Composizione e forwarding

L'idea è che quando un oggetto non ha modo di eseguire un compito localmente, può inviare messaggi ad altri oggetti chiedendo supporto. Se questi oggetti di supporto sono parte dell'oggetto chiamante, si parla di composizione fra oggetti.

L'invio di un messaggio da un oggetto all'altro viene chiamato forwarding. Lo scambio di messaggio serve per comunicare cosa deve essere fatto.

Il forwarding delega la classe interna a fare delle operazioni senza riciclare il codice nella classe esterna, ovvero sfrutto quello che c'è scritto dentro ai metodi della classe figlia.

Limiti del forwarding

La combinazione di composizione fra oggetti e forwarding risulta simile all'ereditarietà: l'oggetto esterno non reimplementa le funzionalità dell'oggetto interno, per cui si ha il riuso se l'implementazione dell'oggetto interno viene migliorata, il miglioramento si trasmette.

che i dati passati dalla Classe1 alla Classe2 siano dati manipolabili dai metodi della Classe2. Delega La delega differisce dal forwarding in due aspetti:
  • i messaggi contendono un riferimento al chiamante (sender): i metodi di Classe2 hanno come parametro proprio l'interfaccia!
  • il delegato deve poter accedere ad un'interfaccia di delega esposta dal delegante
L'interfaccia di delega svolge un ruolo simile all'interfaccia di implementazione. Il delegante passa per composizione un'attività alla classe interna (delegato) e per essere sicuri che il messaggio è adatto viene utilizzata un'interfaccia di delega, che viene implementata dal delegante e utilizzata dal delegato. Il messaggio passato è l'oggetto delegante, per essere sicuri

Che il dato sia manipolabile. Quindi si ha che: la Classe1 implementa l'interfaccia di delega, passa se stessa (this) alla Classe2 che usa l'interfaccia, per cui si è sicuri che il dato sia manipolabile. Il parametro del metodo di Classe2 deve essere dello stesso tipo dell'interfaccia.

Ereditarietà e delega: conclusioni

Il passaggio del riferimento al sender assieme all'interfaccia di delega consentono di simulare il self comune e quindi di superare le limitazioni del forwarding. Si ha però che, quando si cerca di riprodurre le caratteristiche più potenti dell'ereditarietà, emergono gli stessi problemi di accoppiamento che sono alla causa del problema della classe base fragile. Il problema è generale: i meccanismi molto potenti sono anche potenzialmente pericolosi e richiedono cautela. Oggi si tende a riconoscere alla delega una funzione complementare all'ereditarietà di implementazione.

Esempio Sortable3-4 Java

Reflection

La Reflection è la capacità di esplorare dinamicamente (a tempo di esecuzione) la struttura degli oggetti, delle classi e delle interfacce e di interagire con essi.

Si distinguono due aspetti:

  • Introspezione: esplorazione di classi, oggetti e interfacce. È consentita grazie al fatto che la struttura delle classi viene salvata in un'area dei metadati.
  • Interazione dinamica: con classi e oggetti. È la possibilità di eseguire dei metodi in modo dinamico, ad esempio evocando il metodo con una stringa contenente il suo nome.

Costituisce la base del modello di componenti di Java: i Java Beans.

Quando si utilizza un componente di terze parti e lo si ingloba nel progetto, per sapere come usarlo si può:

  • Utilizzare il codice sorgente (non sempre possibile).
  • Se si ha solo il codice oggetto, basta sapere come si chiama per scoprire dinamicamente attributi e metodi da utilizzare.

Gli IDE consentono di aggiungere questi componenti e leggere attraverso la reflection.

come è fatta la classe.Introspezione Per un oggetto, è la capacità di determinare la classe a cui appartiene. Per una classe, è la possibilità di ottenere informazioni su attributi, metodi, costruttori, interfacce, superclasse e modificatori. Per un interfaccia, è la possibilità di scoprire i metodi e le costanti contenute nella dichiarazione. Interazione dinamica Consente di: - Creare un'istanza di una classe il cui nome è noto solo a runtime - Elencare le interfacce implementate da una classe - Enumerare i costruttori, i metodi e i campi definiti da una classe - Leggere e scrivere il valore di un attributo di un oggetto in base al nome - Invocare un metodo in base al nome - Creare un nuovo array la cui dimensione e il cui tipo di elementi sono noti solo a runtime - Modificare i componenti di un array Caricamento dinamico di una classe Per le classi note a tempo di compilazione, il sistema Java provvede automaticamente al caricamento. Se la classe èsconosciuta a tempo di compilazione ma il suo nome è notoruntime, si può caricare dinamicamente: <Class c = Class.forName("MyClass");> L'invocazione del metodo Class restituisce un puntatore all'oggetto. È il meccanismo utilizzato da JDBC per caricare il driver di uno specifico DBMS: <Class.forName("MySQL.JDBCDriver");> La classe JDBCDriver può essere sconosciuta al momento in cui si compila il programma; basta cambiare il parametro per cambiare driver dinamicamente. La classe Class è un descrittore di tipo. Un'istanza di Class consente di accedere alle informazioni relative a una classe o a un'interfaccia. <Class c = cnt.getClass();> C è un puntatore che contiene i metadati dell'oggetto su cui è.
Dettagli
Publisher
A.A. 2019-2020
170 pagine
1 download
SSD Ingegneria industriale e dell'informazione ING-INF/05 Sistemi di elaborazione delle informazioni

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher elefante1234 di informazioni apprese con la frequenza delle lezioni di Ingegneria del software e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università degli Studi di Ferrara o del prof Luglio Fabrizio.