Una o più classi che implementano gli stessi metodi possono appartenere alla stessa interfaccia, queste classi forniscono, allora, gli stessi servizi (anche se l'implementazione dei metodi può comunque differire e caratterizzare quindi il servizio). Va subito precisato che un'interfaccia (non quella grafica che pure ho intenzione di spiegare) non è una classe e non permette pertanto l'istanza di nuovi oggetti. Viene invece concesso l'uso dei riferimenti a oggetti che partecipano all'interfaccia.
Detto in altre parole, un'interfaccia elenca i servizi (i metodi) che le classi (quelle che implementano i metodi dell'interfaccia) sono in grado di offrire. Attenzione, l'interfaccia non implementa i metodi che la compongono, si limita a riportarne la firma ed eventualmente qualche costante poi ereditata dalle classi (le costanti di un'interfaccia sono di default di tipo
public static final
, anche quando ciò non è esplicitamente scritto). Ecco come va descritta un'interfaccia:
public interface Playable {
int playCard();
int attack();
int defend();
}
Tutti i metodi di un'interfaccia sono di default considerati
public
, anche se alcuni programmatori per abitudine o completezza spesse volte ne riportano per intero l'identificatore. Tutte le classi che intendono partecipare all'interfaccia Playable
devono, allora, implementare i metodi playCard()
, attack()
e defend()
. Attenzione a non riportare erroneamente, nelle classi, la firma dei metodi da implementare. Ecco perché per completezza alcuni programmatori scrivono per esteso le firme dei metodi di un'interfaccia (molte volte si copia e incolla il codice e poi si incappa nell'errore, dimenticando che i metodi di un'interfaccia sono sempre pubblici). Per dichiarare la partecipazione di una classe a un'interfaccia si ricorre all'identificatore implements
. Ad esempio:
class Creature extends Card implements Playable {
...;
}
oppure:
class Land extends Card implements Playable {
...
}
Ricordate, l'istruzione
Playable newCreature=new Playable();
è errata! L'istruzione Playable newCreature;
è invece lecita! Per permettere il confronto di oggetti, Java ha pensato all'interfaccia Comparable
. Tutte le classi che vogliono partecipare all'interfaccia (il servizio è quindi il confronto di oggetti) devono implementare il metodo compareTo()
e segnalare dunque la partecipazione, con implements
, all'interfaccia stessa.Perché allora non realizzare la classe astratta
Playable
, con i metodi astratti playCard()
, attack()
e defend()
? In questo modo le classi Card
e Creature
potrebbero estendere la classe astratta e fornire un'implementazione dei metodi. Perché non fare così?La risposta a questa domanda è molto semplice e aiuta a comprendere l'importanza delle interfacce. Java non consente l'ereditarietà multipla, questo significa che una classe può estendere solo una classe! Una classe può invece implementare più interfacce e ciò favorisce la partecipazione della stessa a più servizi, cosa altrimenti impossibile da realizzare se il servizio fosse realizzato con una classe astratta.
public interface Taps {
boolean isTap();
boolean tapIt();
}
In base a quanto appena detto, è possibile incontrare codice simile a questo:
class Creature extends Card implements Playable, Taps {
public int playCard() {
...
}
public int attack() {
...
}
public int defend() {
...
}
public boolean isTap() {
...
}
public boolean tapIt() {
...
}
}
oppure:
class Land extends Card implements Playable, Taps {
public int playCard() {
...
}
public int attack() {
...
}
public int defend() {
...
}
public boolean isTap() {
...
}
public boolean tapIt() {
...
}
}
L'istruzione
class Creature extends Card, Playable, Taps
non è ammessa da Java, ora siete stati avvisati.
Nessun commento:
Posta un commento