Andiamo adesso ad analizzare l’ultimo dei concetti relativi alla programmazione ad oggetti, ovvero le interfacce.
Cosa sono le interfacce in Java?
Molto spesso, le interfacce vengono confuse con le classi astratte, dato che dal punto di vista logico sono molto simili. Tuttavia, le interfacce possono essere intese come un’evoluzione delle classi astratte e permettono, di fatto, di simulare l’ereditarietà multipla.
Vantaggi delle interfacce
Il vantaggio principale di un’interfaccia, essendo comunque una classe con proprietà particolari, è che oltre ad essere estesa può essere implementata. La differenza tra estendere e implementare è molto grande: una classe può essere ereditata solo ed esclusivamente una volta, mentre una classe può implementare infinite interfacce, permettendo così l’ereditarietà multipla.
Per quanto riguarda le interfacce, abbiamo alcune limitazioni rispetto alle classi astratte. In un’interfaccia possono essere dichiarati esclusivamente metodi astratti e non possono essere dichiarate variabili, ma solo costanti. Queste limitazioni non devono essere viste come una mancanza del linguaggio Java, in quanto risultano essere, in realtà, un punto di forza. Con le interfacce si può simulare l’eredità multipla e potendo dichiarare solo costanti e metodi astratti, si ottiene un’ereditarietà multipla controllata. Questo è un grosso vantaggio: l’ereditarietà multipla selvaggia, ovvero il fatto di ereditare da più classi variabili e metodi già implementati, spesso mina la robustezza dell’intera applicazione.
Dichiarazione e implementazione delle interfacce
Vediamo adesso, dal punto di vista del codice, come si dichiara un’interfaccia e come la si implementa:
La dichiarazione avviene usando la parola chiave interface in questo modo:
public interface Prova {
//contenuto
}
L’implementazione dell’interfaccia è invece possibile utilizzando la parola chiave implements:
public class Implementazione implements Prova {
//contenuto
}
Per ottenere l’ereditarietà multipla, basta accodare il nome delle interfacce che si vogliono implementare dopo la parola chiave implements, separate da virgola.
L’importanza dell’astrazione
Le interfacce conferiscono a un’applicazione uno dei concetti fondamentali su cui si basa la programmazione ad oggetti: l’astrazione. Infatti, come abbiamo detto, l’astrazione consente di definire un concetto in maniera molto sintetica, focalizzandosi solo sugli aspetti fondamentali che modellano un determinato concetto. Dunque, cosa c’è di più astratto di un’interfaccia, nella quale non può essere implementato nessun metodo? Praticamente niente, dunque l’interfaccia risulta essere il massimo livello di astrazione possibile per i dati.
Applicazioni pratiche delle interfacce
Purtroppo, non è possibile comprendere al meglio la vera essenza delle interfacce fino a quando non si sviluppano applicazioni di grandi dimensioni, dove l’organizzazione delle classi e le varie relazioni di ereditarietà devono essere monitorate costantemente per evitare la formazione di bug pericolosi. Basti sapere che Java sfrutta le interfacce per implementare uno dei suoi cavalli di battaglia: la creazione dei thread, consentendo così di conferire la caratteristica di multithreading all’applicazione. Senza le interfacce, ciò non sarebbe stato possibile!
Il lettore potrà dunque vedere esempi più concreti per quanto riguarda l’uso delle interfacce quando tratteremo i Thread in questa guida.