web-dev-qa-db-fra.com

L'importance des interfaces en Java

Supposons que nous ayons deux classes, Tiger et Aeroplane. Un point commun à ces deux types est la vitesse. Je sais qu'il serait illogique de créer une super-classe ClassWithSpeed et d'en dériver les sous-classes Aeroplane et Tiger . Au lieu de cela, il est préférable de créer une interface contenant la méthode speed(), puis de l'implémenter dans Aeroplane et Tiger. Je comprends ça. Mais, nous pouvons faire la même chose sans interfaces. Nous pourrions définir la méthode speed() dans Aeroplane et la méthode speed() dans Tiger. Le seul (éventuellement très grand) défaut serait que nous ne pourrions pas "atteindre" les objets de Tiger et Aeroplane par une référence d'interface.

Je suis débutant en Java et en POO, et je serais très reconnaissant si quelqu'un m'expliquait le rôle des interfaces . Salut!

42
Want

Ses:

public int howFast(Airplane airplane) {
    return airplane.speed();
}

public int howFast(Tiger tiger) {
    return tiger.speed();
}

public int howFast(Rocket rocket) {
    return rocket.speed();
}

public int howFast(ThingThatHasntBeenInventedYet thingx) {
    // wait... what? HOW IS THIS POSSIBLE?!
    return thingx.speed();
}

...

contre

public int howFast(Mover mover) {
    return mover.speed();
}

Maintenant, imaginez que vous deviez revenir en arrière et modifier toutes ces fonctions howFast dans le futur. 

Interface ou non, chaque classe devra implémenter ou hériter de la méthode speed(). Une interface vous permet d'utiliser plus facilement ces classes disparates, car chacune d'elles a promis de se comporter d'une certaine manière. Vous appelez speed(), et ils renverront une int, de sorte que vous n'avez pas à écrire de méthodes distinctes pour chaque classe possible. 

Lorsque vous constatez que vous devez gérer la vitesse différemment en raison d'une avancée dans la physique relativiste, il vous suffit de mettre à jour les méthodes appelant speed(). Lorsque votre arrière-petite-fille écrit une classe pour HyperIntelligentMonkeyFish, elle n'a pas à démonter votre ancien fichier binaire et à apporter des modifications pour que votre code puisse surveiller et contrôler son armée mutante. Elle n'a qu'à déclarer que HyperIntelligentMonkeyFish implements Mover.

70

Les interfaces permettent à Java, puisqu'il est typé de manière statique, de contourner plusieurs limitations d'héritage correspondant au degré que les concepteurs de langage jugent intéressant.

Dans un langage dynamique (comme Python, Ruby, etc.), vous pouvez simplement appeler la méthode speed sur n’importe quel objet quelconque et découvrir au moment de l’exécution si elle existe ou non.

Java, en revanche, est typé de manière statique, ce qui signifie que le compilateur doit accepter que la méthode soit disponible à l'avance. La seule façon de faire cela sur des classes qui ne partagent pas une ascendance commune, et qui peut uniquement avoir Object en commun, est une interface.

Etant donné que les objets peuvent implémenter un nombre arbitraire d'interfaces, cela signifie que vous bénéficiez des avantages d'un héritage multiple (un seul objet pouvant se présenter sous la forme de plusieurs objets différents pour des méthodes différentes) sans les inconvénients (implémentations conflictuelles dans les deux super classes).

Avec Java 8, les concepteurs du langage ont conclu que les interfaces sans aucune implémentation étaient trop restrictives (ils n’aimaient pas ma solution je suppose ;-)), de sorte qu’elles permettent une implémentation par défaut, élargissant ainsi le multi- options d'héritage des interfaces, tout en essayant d'éviter le problème d'implémentation en conflit via un ensemble complexe de règles de priorité afin qu'il y ait une implémentation par défaut non ambiguë à exécuter.

8
Yishai

J'essaie d'expliquer l'avantage de l'interface avec l'exemple suivant-

supposons que vous ayez une autre classe où vous devez utiliser le tigre ou l’avion comme paramètre. Donc, en utilisant l'interface, vous pouvez appeler en utilisant

someObject.someMethod(ClassWithSpeed)

mais si vous n'utilisez pas l'interface, vous pouvez utiliser

someObject.someMethod(Tiger)
someObject.someMethod(AeroPlane)

Maintenant que devriez-vous faire? Votre réponse probable sera comme, "I will use two overloaded method".

C'est bon jusqu'à présent, mais

Supposons que vous deviez ajouter plus d'options (voiture, vélo, lapin, tortue, etc. 100 autres). Alors, que ferez-vous pour faire le changement de votre code existant ?? vous aurez besoin de changer beaucoup de choses .. 

L'exemple général ci-dessus n'a qu'un seul but. C'est-à-dire 

"nous avons besoin d’une interface pour créer un meilleur design réutilisable et correctement orienté objet"

N.B.  

  1. si vous êtes sûr que le programme est trop petit et que vous n'aurez jamais besoin de les changer, alors je pense qu'il est acceptable de les implémenter sans interface
6
stinepike

La définition d'une interface vous permet de définir des méthodes qui fonctionnent non seulement sur Airplane et Tiger, mais également sur d'autres classes partageant la même interface.

Par exemple, supposons que votre interface soit IObjectWithSpeed. Vous pouvez ensuite définir une méthode comme celle-ci - dans une classe unique qui opère sur des objets IObjectWithSpeed.

  public double calculateSecondsToTravel( IObjectWithSpeed obj, double distance ) {
       return distance / obj.getSpeed();
  }

Les interfaces nous permettent de satisfaire le principe ouvert/fermé - ouvert pour extension, mais fermé pour modification. La mise en œuvre unique de la méthode ci-dessus n'a pas besoin d'être modifiée car de nouvelles classes sont implémentées qui implémentent IObjectWithSpeed. 

5
Andy Thomas

Une interface n'est pas simplement une signature de méthode.

C'est un type qui représente un contrat. Le contrat est la chose, pas les signatures de méthode. Lorsqu'une classe implémente une interface, c'est parce qu'il existe un contrat pour un comportement partagé que la classe a intérêt à implémenter en tant que type. Ce contrat est implémenté via les membres spécifiés, qui sont généralement des corps de méthodes, mais peuvent également inclure des champs finaux statiques.

Il est peut-être vrai qu'un tigre et un avion peuvent tous deux être exprimés sous la forme d'un type avec un comportement commun implémenté via speed () ... et si c'est le cas, l'interface représente alors le contrat pour exprimer ce comportement.

3
scottb

En plus d'être descriptives pour la fonctionnalité de ces classes, les méthodes d'une interface pourraient être utilisées sans aucune connaissance sur les classes l'implémentant, même pour les classes qui n'étaient pas encore définies.

Ainsi, par exemple, si vous avez besoin d'une classe Transport qui calcule des itinéraires efficaces, vous pouvez lui attribuer une classe qui implémente ClassWithSpeed en tant que paramètre et utilisez sa méthode speed() pour calculer ce dont elle a besoin. De cette façon, vous pourriez l'utiliser avec notre classe Aeroplane, mais aussi avec toute classe que nous définirons plus tard, disons Boat. Java veillera à ce que, si vous souhaitez utiliser une classe en tant que paramètre de Transport, il implémente ClassWithSpeed et que toute classe implémentant ClassWithSpeed implémente la méthode speed() pour pouvoir être utilisée.

3
anana

Je veux entrer dans beaucoup de détails théoriques, mais vais essayer d'expliquer en utilisant cet exemple.

Prenez en compte API JDBC. C'est une API utilisée pour traiter les options liées à la base de données en Java. Maintenant, il y a tellement de bases de données dans l'industrie. Comment pourrait-on écrire des pilotes pour cela? Eh bien, l'approche rapide et sale peut consister en une propre implémentation en écriture utilisant nos propres classes et API.

Mais pensez du point de vue du programmeur. Vont-ils commencer à apprendre l'API de DATABASE DRIVER tout en utilisant une base de données différente? La réponse est non.

Alors, quelle est la solution au problème? Juste avoir une API bien définie que n'importe qui peut étendre pour sa propre implémentation.

Dans l'API JDBC, certaines interfaces sont Connexion, ResultSet, PreparedStatement, Instruction, etc. Chaque fournisseur de base de données implémentera l'interface et écrira sa propre implémentation à cet effet. Résultat ? : Effort réduit du développeur et facilité de compréhension. 

Maintenant, en quoi cette implémentation personnalisée pourrait-elle consister? C'est simple. Ils font quoi, prenez l’interface ResultSet par exemple et implémentez-le. Quelle que soit la méthode que le ResultSet renvoie, renvoyez la classe qui implémente l’interface ResultSet comme celle-ci.

ResultSet rs = new ResultSetImpl (); // c'est ce qu'ils font en interne.

Donc, les interfaces sont comme des contrats. Ils définissent ce que votre classe est capable de faire et donnent à votre application une grande flexibilité. Vous pouvez créer vos propres API en utilisant correctement les interfaces.

J'espère que cela vous aide.

3
trapaank

L'interface (en tant que construction de langage) est utilisée par le compilateur pour prouver que l'appel de méthode est valide et vous permet de faire interagir les classes dépendantes avec la classe d'implémentation tout en ayant le moins de connaissances possibles sur la classe d'implémentation.

1
Ryan Ransford

Au niveau de la langue, la seule utilisation des interfaces est, comme vous l'avez mentionné, de pouvoir faire référence à différentes classes de manière commune. Cependant, au niveau des personnes, l’image est différente: IMO Java est puissant lorsqu’il est utilisé dans de grands projets où la conception et la mise en œuvre sont effectuées par des personnes distinctes, souvent par des sociétés distinctes. Désormais, au lieu d'écrire une spécification sur un document Word, les architectes système peuvent créer un ensemble de classes que les implémenteurs peuvent ensuite insérer directement dans leurs IDE et commencer à les utiliser. En d'autres termes, il est plus pratique de ne pas déclarer que "la classe X implémente les méthodes Y et Z afin de pouvoir être utilisée dans le but A, mais que" la classe X implémente l'interface A "

1
Bobby Marinoff

Avez-vous essayé d'utiliser la composition à la place?, Si je veux que deux classes différentes héritent des mêmes capacités, j'utilise une classe qui prend un objet du type utilisé en utilisant des classes abstraites et en vérifiant les instances. Les interfaces sont utiles pour forcer l'inclusion de méthodes dans la classe, mais ne nécessitent aucune implémentation ou pour que 2 équipes de codeurs travaillent sur différentes zones de codage.

Class Tiger {
  public MovingEntity mover;

 public Tiger(){

  mover.speed=30;
  mover.directionX=-1;
  mover.move(mover);

 }

}
Class Plane {
  public MovingEntity mover;

 public Plane(){
  mover.speed=500;
  mover.directionX=-1;
  mover.move(mover);

 }


Abstract Class Moverable(){
  private int xPos;
  private int yPos;
  private int directionX;
  private int directionY;
  private int speed;


Class MovingEntity extends Moverable {
 public void move(Moverable m){
   if(m instanceof Tiger){

      xPos+=directionX*speed;
      yPos+=directionY*speed;

   }else if(m instanceof Plane){
      xPos+=directionX*speed;
      yPos+=directionY*speed;

   }
 }
1
David Ryan

C'est une question très large pour donner une réponse simple. Je peux recommander un livre Interface Oriented Design: With Patterns . Cela explique tout le pouvoir des interfaces. Et pourquoi nous ne devrions pas les éviter.

1
Mikhail

Parce que créer une interface vous donne Polymorphisme , dans toutes ces classes, à savoir Tiger et Airplane.

Vous pouvez étendre une classe (abstraite ou concrète) lorsque la fonctionnalité de la classe de base sera également au cœur de la fonctionnalité de votre classe enfant.

Vous utilisez des interfaces lorsque vous souhaitez ajouter une fonctionnalité augmentée à votre classe en plus de ses fonctionnalités principales. Donc, utiliser des interfaces vous donnerait un polymorphisme même quand ce n'est pas la fonctionnalité principale de votre classe (parce que vous avez signé un contrat en implémentant l'interface). C'est un avantage énorme par rapport à la création d'une méthode speed () avec chaque classe.

0