Laboratorio di Ingegneria del Software -...

42
Laboratorio di Ingegneria del Software Laboratorio di Ingegneria del Software Prof. Pierluigi Sanpietro, Marcello Bersani, Alessandro Giusti, Luigi Cardamone 

Transcript of Laboratorio di Ingegneria del Software -...

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 eventi­AWT

Laboratorio di Ingegneria del Software

3Esercizio 1 – schema UML

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 1

Implementate ...

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

23Schema UML

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

32Schema UML

Laboratorio di Ingegneria del Software

33Schema UML

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

Event­driven 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.• Event­handler: 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