Sei sulla pagina 1di 45

Classi e relazioni tra classi

Da UML a JAVA
Implementare una classe (1)
Implementare una classe (2)
public class A {
private String attribute1;
private int attribute2;

public A() {
super();
}

public A(String a1, int a2) {


super();
this.attribute1 = a1;
this.attribute2 = a2;
}

public void method_A() { … }


public int method_B(int p1, int p2) { … }
private void method_C(int a1) { … }
protected void method_D() { … }
public String getAttribute1() { … }
public void setAttribute1(String s) { … }
public int getAttribute2() { … }
public void setAttribute2(int a) { … }
}
Generalizzazione (1)
• La relazione di generalizzazione / specializzazione si
implementa tramite ereditarietà
• A eredita gli attributi e i metodi della classe B (solo quelli
consentiti dagli specificatori di visibilità)
• È una relazione del tipo: «A è un B» (ad es. Cane è un
Animale)
Generalizzazione (2)
public class B {
public B() {

}

}

public class A extends B {


public A() {
super();

}

}
Generalizzazione (3)
• un oggetto di tipo A può essere utilizzato come se
fosse un oggetto di tipo B (polimorfismo)
– utile per il passaggio di parametri ai metodi
public static void main(String args[]) {

B b0 = new B();
b0.function_B();

A a0 = new A();
a0.function_A();
a0.function_B();

B b1 = new A();
b1.function_B();
b1.function_A(); //errore

}
Generalizzazione: polimorfismo (1)
Generalizzazione: polimorfismo (2)
public class Poligono {
public void disegna() {
System.out.println("Poligono generico.");
}
}

public class Quadrato {


@Override
public void disegna() {
System.out.println("Quadrato.");
}
}

public class Trapezio {


@Override
public void disegna() {
System.out.println("Trapezio.");
}
}
Generalizzazione: polimorfismo (3)
public class Canvas {
public void disegnaPoligono(Poligono lPoligono) {
lPoligono.disegna();
}
}

public class ProgrammaDisegno()


public static void main(String[] args) {
Quadrato mQuadrato = new Quadrato();
Trapezio mTrapezio = new Trapezio();
Pentagono mPentagono = new Pentagono();

Canvas mCanvas = new Canvas();


mCanvas.disegnaPoligono(mQuadrato);
mCanvas.disegnaPoligono(mTrapezio);
mCanvas.disegnaPoligono(mPentagono);
}
}
Generalizzazione (7)
• In Java non esiste il concetto di Ereditarietà Multipla
• Una classe può ereditare solo da una classe alla volta
• Permette di evitare ambiguità
– quale metodo accelera() deve essere richiamato?
Ridefinizione dei metodi ereditati (1)
• Una classe figlia può ridefinire i metodi della
classe padre se è necessario
• Il metodo della classe figlia deve avere la stessa
firma del metodo che va a ridefinire nella classe
padre
• nella classe figlia il metodo deve essere
etichettato con l’annotazione @Override
• Per richiamare il metodo della classe padre, la
classe figlia può utilizzare il riferimento alla classe
padre ‘super’
Ridefinizione dei metodi ereditati (2)
public class B {
public void doWork() {

}

}

public class A extends B {


@Override
public void doWork() {
super.doWork();

}

}
Osservazioni
• Una classe definita final non può essere
ereditata. Non può avere sottoclassi
– Es, la classe String è final
• Un metodo final non può essere sovrascritto
(di tale metodo non può essere fatto
l’override)
Ereditarietà del Costruttore
• I costruttori non vengono ereditati.
• All’interno di un costruttore è possibile
richiamare il costruttore della superclasse tramite
l’istruzione
super(<listaParametri>);
• Se il costruttore della superclasse non è
esplicitamente chiamato, il compilatore inserisce
automaticamente il codice che invoca di default il
costruttore della superclasse.
• Eclipse inserisce automaticamente l’istruzione
super();
Implementazione di un’interfaccia (1)
• Un’interfaccia è l’aspetto esteriore di una
classe
– Ci dice come è possibile interagire con oggetti che
la implementano
– In particolare, è l’elenco dei suoi metodi pubblici
Implementazione di un’interfaccia (2)
public interface B {
public int method_B(int a, int b);
}

public class A implements B {


public A() {
super();
}

public int method_B(int a, int b){


//implementazione
//…
}
}
Esempio di uso di un’interfaccia (3)
• È possibile per una classe implementare più di
una interfaccia
Esempio di uso di un’interfaccia (4)

public interface Encoder {


public byte[] encode(byte[] b);
}

public interface Decoder {


public byte[] decode(byte[] b);
}

public class Converter implements Encoder, Decoder {



}
Osservazioni sulle Interfacce
• Una classe che dichiara di implementare una o più
interfacce deve necessariamente implementare tutti i
metodi delle interfacce.
– Nel caso contrario ci sarà un errore di compilazione.
• Una interfaccia può contenere solo metodi astratti e
costanti. Non può contenere:
– costruttori, variabili statiche, variabili di istanza e metodi
statici.
– Le constanti in java sono connotate dalla parola chiave
"final"
– Una costante d’interfaccia può anche essere dichiarata
static; sarà implicitamente "final"
Classi astratte (1)
• Una classe astratta può essere vista come un’interfaccia che contiene
l’implementazione di alcuni metodi comuni
• Può contenere tutte le entità normalmente presenti in una classe: metodi
e attributi
• All’interno di una classe astratta ci sono uno o più metodi astratti: metodi
dichiarati, ma non definiti (cioè senza implementazione)
• Le classi astratte non possono essere istanziate perché contengono metodi
non implementati
• Permettono di raggruppare il codice comune in una sola classe, rendendo
obbligatoria la specializzazione di uno o più metodi nelle classi figlie
• Una classe figlia che non definisce un metodo astratto, sarà a sua volta
astratta
• Il meccanismo di implementazione delle classi astratte è l’ereditarietà, per
cui:
– È possibile implementare una sola classe astratta alla volta
– Bisogna etichettare il metodo implementato con l’annotazione @Override
Classi astratte (2)
Classi astratte (3)
public abstract class FiguraGeometrica {
private int colore;
private boolean riempito;
private String tipoForma;

public FiguraGeometrica(String tf){ this.tipoForma=tf; }


public int getColore(){ return this.colore; }
public void setColore(int c){ this.colore = c; }
public boolean getRiempito(){ return this.riempito; }
public void setRiempito(boolean r){ this.riempito = r; }
public String getTipoForma(){ return this.tipoForma; }
public void setTipoForma(String t){ this.tipoForma = t;}

public abstract double getPerimetro();


public abstract double getArea();
}
Classi astratte (4)
public class Cerchio extends FiguraGeometrica {
private double raggio;

public Cerchio(double r){


super("Cerchio");
this.raggio = r;
}
public double getRaggio(){ return this.raggio; }
public void setRaggio(double r){ this.raggio = r; }

@Override
public double getPerimetro() {
return 2 * 3.14 * this.raggio;
}
@Override
public double getArea() {
return 3.14 * this.raggio * this.raggio;
}
}
Classi astratte (5)
public class Rettangolo extends FiguraGeometrica {
private double altezza;
private double base;

public Rettangolo(double base, double altezza){


super("Rettangolo");
this.base = base;
this.altezza = altezza;
}

@Override
public double getPerimetro() {
return 2 * (this.base + this.altezza);
}
@Override
public double getArea() {
return (this.base * this.altezza) / 2;
}
Interfacce vs Classi Astratte
• Tutti i metodi in un’interfaccia sono implicitamente astratti;
una classe astratta può avere metodi non astratti
• Una classe può implementare più interfacce, ma ereditare
da una sola classe astratta
• I metodi di un’interfaccia devono essere tutti implementati;
le classi che ereditano da una classe astratta possono non
implementare tutti i metodi diventando a loro volta astratte
• Le variabili definite in un’interfaccia possono essere solo
final (costanti)
• I membri di un’interfaccia sono implicitamente pubblici; le
classi astratte possono definire diversi livelli di visibilità
Dipendenza tra classi (1)

• Tra due classi A e B c’è una dipendenza


(funzionale) se:
– Un oggetto della classe A invia un messaggio ad
uno della classe B
– Un oggetto della classe A crea un’istanza della
classe B
– Un oggetto della classe A riceve un messaggio che
ha come argomento un oggetto della classe B
Dipendenza tra classi (2)
public class A {

public void method_A() {

B b = new B(); Crea un’istanza della classe B




b.method_B(123); Manda un messaggio alla classe B

}

}
Dipendenza tra classi (3)
public class A {

public void method_A(B b) {

c = b.getField(); Riceve come parametro un
… oggetto della classe B
}

}
Associazione tra classi

• Tra due classi A e B c’è un’associazione se:


– Un oggetto della classe A ha un attributo i cui valori
sono istanze o collezioni di istanze della classe B
• Due casi particolari di associazione sono
aggregazione e composizione
public class A {
B myB;
… Ha un attributo di tipo B
}
Associazione tra classi: molteplicità (1)

myB
public class A {
B myB;
myB

}

• Si traducono allo stesso modo


• Nel secondo caso la variabile può essere NULL
Associazione tra classi: molteplicità (2)
public class A {
B[] arrayB;
arrayB …
}
arrayB public class A {
ArrayList<B> arrayB;

}
• Si traducono allo stesso modo
• Nel primo caso l’array può essere vuoto
• Possiamo utilizzare o un array o una Collection (ad
esempio, un ArrayList)
Associazione tra classi: navigabilità
Monodirezionale public class A {
B myB;
myB

}
In questo caso B non ha visibilità di A.

Bidirezionale public class A {


B myB;
myB

myA }
public class B {
A myA;

}
Associazione tra classi: nome
• Il nome della relazione diventa il nome della variabile
relativa all’oggetto
• Il nome dell’associazione non deve essere uguale a
quello dell’entità collegata

public class Cliente {


ArrayList<Ordine> clientOrders;

}
public class Ordine {
Cliente buyer;

}
Associazione tra classi:
associazione riflessiva

folder

public class Directory {


ArrayList<File> files;
ArrayList<Directory> children;
Directory parent;

}
Associazione tra classi: aggregazione
myB

• È una particolare associazione


• Esprime la relazione A contiene debolmente oggetti B
• L’oggetto B è contenuto in A, ma ha un ciclo di vita
indipendente da A, ovvero non è istanziato da A
public class A {
B myB;

public void setMyB(B b) { … }


}
Associazione tra classi: composizione
myB

• È una particolare associazione


• Esprime la relazione A contiene fortemente oggetti B
• L’oggetto B è contenuto in A e il suo ciclo di vita dipende
da A, ovvero è istanziato da A
public class A {
B myB;

public A() {
this.myB = new B();
}
}
Classe Associativa
Classe Associativa: una possibile
traduzione
public class Studente() {
ArrayList<Corso> corsi;
}

public class Corso() {


ArrayList<Studente> studenti;
}

public class Esame() {


Studente studente;
Corso corso;
Data data;
int voto;
}
La classe Object (1)
• La classe Object è la superclasse implicita di ogni
oggetto Java
• Definisce il comportamento e le caratteristiche
base di ciascun oggetto
• In particolare il metodo:
– equals() : definisce i dettagli del confronto con un
altro oggetto; per default confronta gli indirizzi di
memoria dei due oggetti
– toString() : definisce la rappresentazione dell’istanza
dell’oggetto come stringa; per default restituisce
l’indirizzo di memoria dell’oggetto
La classe Object (2)
• Poiché ogni oggetto eredita implicitamente da
Object è possibile ridefinire questi metodi per
adattare il metodo alle proprie esigenze
• Per ridefinire questi metodi è preferibile (ma
non necessario) rispettare l’insieme di regole
presenti nella documentazione Java
• Queste regole permettono di mantenere un
funzionamento coerente con quello atteso
(Design By Contract)
La classe Object: toString() (1)
La classe Object: toString() (2)

public class Cliente {


String nome;
String cognome;
String codiceFiscale;

@Override
public String toString() {
return this.nome + " " + this.cognome;
}
}
La classe Object: equals() (1)
La classe Object: equals() (2)
• In particolare è buona norma:
– controllare che l’oggetto passato non sia NULL; nel
caso ritornare false
– controllare che l’oggetto passato non sia l’oggetto
stesso; in questo caso ritornare automaticamente
true
– controllare che l’oggetto passato sia compatibile
con l’oggetto con cui si sta effettuando il
confronto; in particolare, deve essere dello stesso
tipo
La classe Object: equals() (3)

@Override
public boolean equals(Object o) {
if(o != null && this != o && o instanceof Cliente) {
return this.codiceFiscale.equals(o.codiceFiscale);
} else {
return false;
}
}