Parfois, vous voudriez que différentes classes de votre hiérarchie de classe aient un
comportement similaire. Par exemple, si vous écrivez un tableur avec des cellules
qui contiennent différentes valeurs, par exemple des chaînes de caractères, des nombres,
des dates, des équations, etc.
Pour que cela fonctionne, il faut que ces différents objets possèdent un certain nombre de méthodes communes. Un moyen de résoudre ce problème est de trouver l'ancêtre commun dont dérive toute ces classes et d'y ajouter les méthodes dont vous avec besoin. Vous pourrez ensuite utiliser cet ancêtre commun dans votre tableur at appeler les méthodes sans savoir quel élément se trouvera finalement dans la case.
Mais ce n'est pas très pratique, pour la raison toute simple que Object est en général l'ancêtre commun de ces classes et que vous n'allez bien sûr pas vous amuser à modifier Object.
Vous pouvez aussi créer une classe CellValue qui va contenir ces méthodes communes, puis dériver cette classe pour créer la classe chaîne de caractère, la classe nombre, etc. Mais en plus d'un travail important, cette approche crée une relation entre des classes qui ne serait autrement pas du tout nécessaire.
Les interfaces sont un moyen très efficace de résoudre ce problème.
Une interface est une collection de définitions de méthodes (sans implémentation) et de valeur constantes.
On utilise des interfaces pour définir un comportement que pourra ensuite implémenter n'importe quelle classe. Avec l'exemple précédent, on créerait une interface CellAble qui définirait un ensemble de méthodes qu'une valeur de cellule doit implémenter : toString(), draw(), toFloat(), etc.
Définir une interface est similaire à définir une classe. Il faut une déclaration et un corps.
La déclaration est la suivante :
[public] interface NomDeLInterface [extends InterfaceMere] {
Le corps se compose de constantes (les données non constantes sont interdites) et de déclarations de méthodes (sans le corps).
Voici un exemple d'interface :
interface Collection {
int MAXIMUM = 500;
void add(Object obj);
void delete(Object obj);
Object find(Object obj);
int currentCount();
}
Pour implémenter une interface, il faut rajouter à la déclaration de la classe concernée le mot clé implements suivi du nom de l'interface. Ensuite, il faut redéfinir dans la classe toutes les méthodes déclarées dans l'interface.
Par exemple :
class FIFOQueue implements Collection {
void add(Object obj) {
// . . .
}
void delete(Object obj) {
// . . .
}
Object find(Object obj) {
// . . .
}
int currentCount() {
// . . .
}
}
Vous pouvez utiliser les interfaces comme d'autres types. Vous pouvez déclarer des références sur une interface, les passer en paramètre... Mais vous ne pouvez pas en créer d'instances (avec new).
Par exemple, avec l'interface suivante :
interface CellAble {
void draw();
void toString();
void toFloat();
}
Vous pouvez ensuite l'utiliser dans les classe de votre tableur :
class Row {
private CellAble[] contents;
// . . .
void setObjectAt(CellAble ca, int index) {
// . . .
}
// . . .
}