laboratorio di ingegneria del software -...
TRANSCRIPT
Laboratorio di Ingegneria del Software
Laboratorio di Ingegneria del Software
Prof. Pierluigi Sanpietro, Marcello Bersani,Alessandro Giusti, Luigi Cardamone
Laboratorio di Ingegneria del Software
Programma
Esercizio ereditarietà: • costruzione di una gerarchia di classi• Uso operatore instanceof
Esercizio interfacce: • organizzare le FormeGeormetriche realizzate la volta scorsa in
una gerarchia che consenta operazioni di confronto e uguaglianza• Primo uso delle eccezioni
Introduzione eventiAWT
Laboratorio di Ingegneria del Software
4Esercizio 1
Basandosi sul diagramma nella slide, si vuole realizzare la struttura dati essenziale per un semplice sw gestionale.
Implementare le classi Nel main istanziare alcune istanze di Dirigenti e Segretarie,
Universitari e Scolastici in un array di Persone Stampare, per ciascuno,
• Nome• Cognome• codice fiscale • stipendio (per i lavoratori), tasse (per gli studenti)
• Supponiamo che per I lavoratori (Dirigenti e Segretarie) venga fornito il costo orario.• Per gli Studenti è fornita la fascia di reddito che, moltiplicata per un opportuno fattore, consente il calcolo delle tasse scolastiche.
Laboratorio di Ingegneria del Software
Esercizio 1 commenti
Ad una prima analisi getStipendio() e calcolaStipendio() appaiono molto simili.
calcolaStipendio() è usato per ottenere lo stipendio del Lavoratore, in funzione del tipo attuale Manager o Segretaria; perché in queste classi viene implementato (cioè personalizzato) secondo la paga oraria specifica di un Manager o di una Segretaria.
getStipendio() è un semplice getter. Eventualmente può usare calcolaStipendio() qualora il suo valore non sia ancora definito (ad esempio, quando stipendio < 0).
Laboratorio di Ingegneria del Software
Esercizio 1 – operatore instanceof
E' stato chiesto di stampare tasse e stipendi ... ... gli oggetti di tipo Universitario, etc. sono inseriti in un array di
Persone... sorge spontanea la domanda ... COME POSSO SAPERE SE
CHIAMARE IL METODO calcolaTasse() o calcolaStipendio() ????
Persona[] p = new Persona[2];p[0] = new Universitario(...);...
for (Persona pers : p){pers.calcolaTasse() ?
pers.calcolaStipendio()?}
Laboratorio di Ingegneria del Software
Esercizio 1 – operatore instanceof
Bisogna usare l'operatore instanceof
Persona[] p = new Persona[2];p[0] = new Universitario(...);...
for (Persona j : p){
if (j instanceof Studente) ((Studente) j).getTasse();
else((Lavoratore) j).getStipendio();
}
Laboratorio di Ingegneria del Software
Esercizio 1 osservazioni
Notate come Persona sia una classe astratta perché non vogliamo rendere persona istanziabile in quanto oggetto; vogliamo solo creare il tipo per definire la gerarchia
Le uniche classi istanziabili sono Dirigente, Segretaria, Universitario e Scolastico.
Laboratorio di Ingegneria del Software
Esercizio 2 – osservazioni costruttori
Siccome stiamo creando una gerarchia di tipi, ragioniamo un po' sui costruttori
• Se C non definisce alcun costruttore, C eredita il costruttore di default da Object.
• Se C definisce C(...), C non eredita un costruttore di default.
class A {...}class B extends A {...}
• Se cB()/cB(...) non chiama esplicitamente cA()/cA(...) allora viene richiamato implicitamente cA()
• Se non è definito cA() {ma solo cA(...)} e cB()/cB(...) non chiama esplicitamente il cA(...) errore compilazione→
Laboratorio di Ingegneria del Software
Esercizio 2 osservazioni
class A {...}class B extends A {...}
• Se cB()/cB(...) non chiama esplicitamente cA()/cA(...) allora viene richiamato implicitamente cA()
• Se non è definito cA() {ma solo cA(...)} e cB()/cB(...) non chiama esplicitamente il cA(...) errore compilazione→
class B extends A{public B(){
super(); o super(....);}
public B(...){super(); o super(....);}
Laboratorio di Ingegneria del Software
12Esercizio 1 variante
Modificare l'esercizio inserendo un metodo astratto getDescrizione() in persona. • Questo metodo deve stampare nome e CF, attributi noti a tutti gli
oggetti perché propri di Persona ...• e stipendio (per i lavoratori), tasse (per gli studenti)
• OSSERV: in questo caso, solo Studenti e Lavoratori sanno quali metodi e attributi usare!
• All'interno delle classi Studente e Lavoratore, il metodo getDescrizione() verrà definito mediante un'implementazione concreta (cioè scrivo del codice) ...
• ... che utilizza I getters di Persona (informations hiding!!) per ottenere nome e CF ed il proprio attributo tasse o stipendio
Laboratorio di Ingegneria del Software
13Esercizio 1 variante
Nel main inserire un array di Persone e riempirlo con Dirigenti e Segretarie, Universitari e Scolastico.• Stampare i dati di ciascuna persona usando il metodo
getDescrizione()
Laboratorio di Ingegneria del Software
14Overview secondo esercizio
Si vuole realizzare un semplice gestore di immagini 2D, capace di gestire forme geometriche generiche, quali, ad esempio, triangoli, rettangoli, quadrati, cerchi, etc. Ogni elemento geometrico deve poter essere “scalato” di un fattore di scala specifico; tale operazione, qualora eseguita, viene notificata ad un gestore di eventi atto alla registrazione della cronologia delle azioni applicate agli enti geometrici. Inoltre, ogni entità geometrica deve poter essere confrontata con entità affini, al fine di definire, tra essi, una relazione di uguaglianza ed ordine.
Laboratorio di Ingegneria del Software
15Riflessioni
Pensiamo di realizzare solo triangoli, rettangoli e quadrati...per semplicità
dobbiamo pensare a• relazione d'ordine• relazione d'uguaglianza
ed anche alla “scalabilità” degli enti geometrici
Laboratorio di Ingegneria del Software
16Riflessioni
ha senso concepire l'entità FormaGeometrica – generica• ha sicuramente un'area ed un perimetro• in generale non è sempre scalabile – pensiamo ad un eventuale entità Punto...che non ci è richiesta dalla specifica... però potrebbe essere introdotta in un prossimo futuro !!
quindi, sembra, per ora, sensato non rendere scalabile una FormaGeometrica...
• due forme geometriche sono ordinabili? Quando lo sono? Ha senso parlare di ordine? Inoltre...quando due FormeGeometriche sono uguali (da un punto di vista astratto) ?
senza ulteriori specifiche, stabiliamo NOI che due forme sono ordinabili in base all'area ed al perimetro; la nostra relazione d'ordine: FormaG A, B; A>B ⇔ A.area > B.area ∨ (A.area=B.area ⇒ A.perim>B.perim)
Laboratorio di Ingegneria del Software
17Riflessioni
due forme geomtriche sono uguali se hanno area e perimetro uguale? ... potrebbero, ma forse è meglio definire una relazione più precisa...cioè definita non per le forme geometriche, ma per sue sottoclassi.
ha senso concepire l'entità Rettangolo e Triangolo come sottoclassi di FormaGeometrica. Quadrato, è un caso particolare di Rettangolo, dunque una sua sottoclasse.• ha senso quindi parlare di uguaglianza tra Rettangoli, tra Quadrati, tra Triangoli• non ha molto senso però confrontare un Quadrato con un Triangolo• un Quadrato con un Rettangolo? Sì, in generale un Rettangolo è Quadrato se I suoi lati sono uguali (b=h).
Laboratorio di Ingegneria del Software
18Riflessioni
relazione d'ordine: compareTo() relazione d'uguaglianza: equals()
• le precedenti considerazioni consentono di definire correttamente il metodo equals...poi vedremo...
compareTo() deriva dall'interaccia Comparable<T> di Java• è usata per definire correttamente collezioni di oggetti, per i quali si vuole poter gestire gli ordinamenti
• Vedremo che grazie a questo possiamo usare il metodo sort() della classe Collections.
Comparable<T> significa che per la classe che implementa Comparable<T> sussiste una relazione d'ordine con la classe T
FormaGeometrica implementerà Comparable<FormaGeometrica>
Laboratorio di Ingegneria del Software
19Riflessioni
La specifica ci richiede che gli enti geometrici siano scalabili. Costruiamo allora la gerarchia in modo che la scalabilità sia una proprietà astratta...• definiamo un'interfaccia
public interface Scalable{public ... scale(... x);
}
• cosa ritorna scale? x di che tipo? in generale se concepiamo l'operazione di scaling per un entità FormaGeometrica, ha senso che la funzione ritorni una FormaGeometrica. tra l'altro, come possiamo sapere come sarà costruita la gerarchia sotto FormaGeometrica? Non possiamo definire un'interfaccia per ogni sottoclasse!! Non ha senso!
Laboratorio di Ingegneria del Software
20Riflessioni
se un rettangolo viene scalato, potrà diventare un Rettangolo, o un Quadrato, ma sempre una FormaGeometrica. I triangoli...rimarranno triangoli.... ancora FormaGeometrica. Questa è la potenzialità del polimorfismo!
supponiamo che x sia un semplice float (andrebbe bene anche Float() ).
public interface Scalable{public FormaGeometrica scale(float x);
}
Costruiamo classi IMMUTABLE. Rettangoli e quadrati saranno estesi con un Vector<Float>
(dimensione 2) che definisce I lati Triangolo con un Vector<Float> (dimensione 3)
Laboratorio di Ingegneria del Software
21Riflessioni
infine: come definiamo gli attributi area e perimetro di FormaGeometrica? private o protected?
private: sensato, visto che consideriamo FormaGeometrica IMMUTABLE. Perchè? Perchè gli oggetti non si modificheranno durante la loro vita. Quindi un Rettangolo non modificherà i suoi valori di area e perimetro. Inoltre, lo scaling ritorna una nuova FormaGeometrica. Nel costruttore dei sottotipi di FormaGeometrica richiamiamo il suo costruttore. Non abbiamo, però, visibilità nei sottotipi.
protected: attenzione; la visibilità protected diventa public in tutta la gerarchia di sottoclassi e nel package!! dobbiamo essere consci che deleghiamo potere decisionale su queste variabili.
Laboratorio di Ingegneria del Software
22Riflessioni
il metodo scale(), agisce su area e perimetro ma anche sui lati dei Rettangoli, etc. o su attributi propri delle forme
sottotipo di FormaGeometrica !
quindi, FormaGeometrica sarà necessariamente abstract!
scale() non va implementato in FormaGeometrica ... cioè una generica FormaGeometrica non sa come scalarsi ... solo una sua istanza sottotipo può saperlo!
Laboratorio di Ingegneria del Software
24Come implementare FormaGeometrica:compareTo()
data la definizione della relazione d'ordine, dunque implementando compareTo() in FormaG, fissiamo la semantica dell'ordinamento nella superclasse.
ovvero, tutte le sottoclassi devono rispettare questa semantica (x eredità), al massimo rifinirla, senza violarla.
potremmo definirla final (però, attenzione!)
Laboratorio di Ingegneria del Software
25Come implementare FormaGeometrica:compareTo()
proprietà di compareTo() visto come <:• antiriflessività• asimmetria
sgn(x.compareTo(y)) == sgn(y.compareTo(x))• transitività
• x.compareTo(y)==0 ⇒ sgn(x.compareTo(z)) == sgn(y.compareTo(z)), ∀ z
proprietà di compareTo() visto come ≤:• riflessività
che si traduce in (x.compareTo(y)==0) == (x.equals(y))raccomandato da java!
Laboratorio di Ingegneria del Software
26Come implementare FormaGeometrica:compareTo()
public (final) int compareTo(FormaGeometrica other)throws NullPointerException{
//in generale non si deve richiamare super.compareTo() perché magari non lo implementa; solo se sappiamo che esiste
//controllo che other non sia nullif (other == null) throw new NullPointerException();
//controllo che other sia me stessoif (other == this) return 0;
//realizzazione confronto sapendo che il confronto avverrà con una classe o sottoclasse di FormaGeometrica
}
Laboratorio di Ingegneria del Software
27Rettangoli, Quadrati, Triangoli
definiamo i lati come Vector<Float>. private
1° modo: instanziate già il Vector<T> nella dichiarazione della classe
Vector<Float> lati = new Vector<Float>(x);
2° modo: sola definizione nella dichiarazione della classeVector<Float> lati;
• poi ricordiamoci di instanziarlo nel costruttore!lati = new Vector<Float>(x);
ereditano l'implementazione dell'interfaccia scalable...dunque il metodo abstract da FormaGeometrica
Laboratorio di Ingegneria del Software
28Sul metodo Equals()
equals() ovvero relazione di uguaglianza proprietà:
• simmetria• riflessività• transitività• consistenza
la simmetria (e l'asimmetria per compareTo()) crea problemi quando si ha una gerarchia di classi.
la simmetria impone x.equals(y) == y.equals(x)
questo può non accadere se non si implementa bene il metodo in base alle esigenze!!
Laboratorio di Ingegneria del Software
29Come implementare C:equals()
public boolean equals(Object other){//in generale se so che super implementa equals()if (!(super.equals(other)) return false;
//controllo che other non sia nullif (other == null) false;//controllo che other sia me stessoif (other == this) return true;
//controllo che gli oggetti possano essere confrontatiif (getClass() != other.getClass()) return false;if (!(other instaceof C)) return false;
C obj = (C)other; //cast esplicito a me stesso//ora confronto
}
Laboratorio di Ingegneria del Software
30Sul metodo Equals()
se uso if (getClass() != other.getClass()) return false;• impongo che il confronto avvenga tra soli obj della stessa classe• oggetti “fratelli” non possono essere confrontati uso: quando la semantica di equals cambia nella gerarchia spingo il concetto di uguaglianza verso il basso suggerito da Java
se uso if (!(other instanceof C)) return false;• impongo che il confronto avvenga tra obj parenti• oggetti “fratelli” e “figli con padre” possono essere confrontati uso: quando la semantica di equals ha senso per tutte le sottoclassi della gerarchia spingo il concetto di uguaglianza verso l'alto in questo caso, alcune volte ha senso definire equals() come finalATTENZIONE: non è il modo suggerito da Java!!!!!!!!
Laboratorio di Ingegneria del Software
31Sul metodo Equals()
infatti, nella gerarchia A padre di B, se A implementa equals() con instanceof ...
a.equals(b) non crea problemi; b è B ⊆ A b.equals(a) ???
la chiamata a super non crea problemi; avviene un confronto a livello del super tipo
il cast successivo crea problemi inoltre, b deve potersi confrontare con tutti le classi figlie di A
OSSERVAZIONE!!!!! I ragionamenti fatti per equals valgono anche per gli oggetti
confrontati mediante l'interfaccia Comparable (non Comparable<T>) che obbliga l'implementazione del metodo int compareTo(Object o)
Laboratorio di Ingegneria del Software
Esercizio 2 – prima fase
Definire la gerarchia precedente Wrapper dei tipi predefiniti. Possiamo usare Float() invece che float.
Float f = new Float(3.9);
Classe Vector<T>
Vector<Float> v = new Vector<Float>();v.add(new Float(1.5));v.add(new Float(4.6));
Per poter utilizzare Collections.sort(List<T>) deve essere definito il metodo compareTo per la classe T
Collections.sort(v);
Laboratorio di Ingegneria del Software
Esercizio 2 – prima fase
Per poter utilizzare Collections.sort(List<T>) deve essere definito il metodo compareTo per la classe T
Nell'esercizio definiremo:
Vector<FormaGeometrica> v = new Vector<FormaGeometrica>();
v.add(new Rettangolo(new Float(2.0), new Float(3.0)));v.add(new Triangolo(new Float(2.0), new Float(3.0), new
Float(5.0)));
Collections.sort(v);
Laboratorio di Ingegneria del Software
Eventdriven programming
Paradigma di programmazione in cui il flusso di esecuzione è determinato dall'accadimento di eventi gestiti da opportuni moduli software
Tipico delle interfacce grafiche ... ma non solo.
Idea:• Dispatcher: raccoglie gli eventi da processare, tipicamente in una
coda.• Eventhandler: processano uno specifico evento (in base a quello
che sanno fare) producendo un “output” ... fanno, cioè, qualcosa!
• Esempio: I sistemi operativi (interrupt)
Laboratorio di Ingegneria del Software
37Eventi AWT, Listener
...list.actionX(new XEvent())
...
list =l
addListener(XEventListener l)
XEventListener list;
doSomething()
XEventListener
classe generatrice dell'evento
actionX(XEvent())
l'obj che genera l'evento necessita la registrazione del listener che lo “ascolta”
l'evento sarà l'estensione di EventObject; porterà con sé informazioni utili
Laboratorio di Ingegneria del Software
38Definiamo l'evento
ogni evento deve estendere EventObject• può così contenere un qualsiasi tipo di informazione utile
il costruttore di EventObject(Object obj) richiede la specifica dell'oggetto che genera l'evento noi ridefiniamo il costruttore semplicemente richiamando super(obj)
è richiesto import java.util.EventObject
EventObject è un obj particolare che può essere serializzato, implementa l'interfaccia Serializable• idea: trasferire oggetti instanziati da un esecutore (VM) ad un altro remoto, via stream• quindi: gli eventi possono “girare” in un sistema distribuito
Laboratorio di Ingegneria del Software
39Schema UML
public class ScaleEvent extends EventObject {
private static final long serialVersionUID = 1L;private float scale;
public scaleEvent(Object obj, float aScale) {super(obj);scale = aScale;
}}
Laboratorio di Ingegneria del Software
40Definiamo il listener
ogni listener deve implementare un'interfaccia XEventListener la quale, a sua volta, estende la tag interface EventListener• la tag interface EventListener non definisce alcun metodo; è una rappresentazione interna a Java• XEventListener specifica il NOSTRO metodo per la gestione dell'evento/i • parametro: il NOSTRO evento XEvent
è richiesto import java.util.EventListener
import java.util.EventListener;public interface ScaleEventListener extends EventListener {
public void actionScale(ScaleEvent e);}
Laboratorio di Ingegneria del Software
41Definiamo il listener
il listener estende l'interfaccia XEventListener
e.getSource() restituisce il reference all'obj interessato dall'evento
public class ScaleGuard implements ScaleEventListener {
public void actionScale(ScaleEvent e) {
System.out.println("Scaling: " + e.getSource().getClass().toString() + “ “ + e.getScale());
}
}
Laboratorio di Ingegneria del Software
42Uso delle classi
creare una serie di FormeGeometriche – Rettangoli, Triangoli, ... creare una guardia all'azione di Scaling – un Listener registrare la guardia alle forme inserire le forme in una collezione apposita a contenere
FormeGeometriche provare ad ordinare la collezione di FormeGeometriche effettuare operazioni di scaling