venerdì 7 maggio 2010

Java: interfacce

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'istruzionePlayable 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