JavaRush /Blog Java /Random-FR /Interfaces en Java

Interfaces en Java

Publié dans le groupe Random-FR
Bonjour! Aujourd'hui, nous allons parler d'un concept important en Java : les interfaces. Le mot vous est probablement familier. Par exemple, la plupart des programmes informatiques et des jeux ont des interfaces. Au sens large, une interface est une sorte de « télécommande » qui relie deux parties interagissant entre elles. Un exemple simple d’interface de la vie quotidienne est une télécommande de téléviseur. Il connecte deux objets, une personne et un téléviseur, et effectue différentes tâches : augmenter ou diminuer le volume, changer de chaîne, allumer ou éteindre le téléviseur. Un côté (la personne) doit accéder à l'interface (appuyer sur le bouton de la télécommande) pour que l'autre côté puisse effectuer l'action. Par exemple, pour que le téléviseur passe à la chaîne suivante. Dans ce cas, l'utilisateur n'a pas besoin de connaître l'appareil du téléviseur et comment le processus de changement de chaîne est mis en œuvre à l'intérieur. Pourquoi avons-nous besoin d'interfaces en Java - 1Tout ce à quoi l'utilisateur a accès est l'interface . La tâche principale est d'obtenir le résultat souhaité. Quel est le rapport avec la programmation et Java ? Direct :) La création d'une interface est très similaire à la création d'une classe normale, mais au lieu du mot, classnous spécifions le mot interface. Examinons l'interface Java la plus simple et voyons comment elle fonctionne et à quoi elle sert :
public interface Swimmable  {

     public void swim();
}
Nous avons créé une interface Swimmablequi sait nager . C'est un peu comme notre télécommande, qui a un « bouton » : la méthode swim() est « nager ». Comment peut-on utiliser cette « télécommande » ? A cet effet, la méthode, c'est-à-dire Le bouton de notre télécommande doit être implémenté. Pour utiliser une interface, ses méthodes doivent être implémentées par certaines classes de notre programme. Imaginons une classe dont les objets correspondent à la description « sait nager ». Par exemple, la classe canard convient Duck:
public class Duck implements Swimmable {

    public void swim() {
        System.out.println("Duck, swim!");
    }

    public static void main(String[] args) {

        Duck duck = new Duck();
        duck.swim();
    }
}
Que voit-on ici ? Une classe Duckest associée à une interface Swimmableà l'aide du mot-clé implements. Si vous vous en souvenez, nous avons utilisé un mécanisme similaire pour connecter deux classes en héritage, seulement il y avait le mot « extends ». «public class Duck implements Swimmable » peut être traduit littéralement pour plus de clarté : « une classe publique Duckimplémente l'interfaceSwimmable ». Cela signifie qu'une classe associée à une interface doit implémenter toutes ses méthodes. Attention : dans notre classe, Ducktout comme dans l'interface , Swimmableil y a une méthode swim(), et à l'intérieur il y a une sorte de logique. Il s’agit d’une exigence obligatoire. Si nous écrivions simplement «public class Duck implements Swimmable » et ne créions pas de méthode swim()dans la classe Duck, le compilateur nous donnerait une erreur : Duck n'est pas abstrait et ne remplace pas la méthode abstraite swim() dans Swimmable. Pourquoi cela se produit-il ? Si nous expliquons l'erreur en utilisant l'exemple d'un téléviseur, il s'avère que nous donnons à une personne une télécommande avec un bouton « changer de chaîne » d'un téléviseur qui ne sait pas changer de chaîne. A ce stade, appuyez autant que vous le souhaitez sur le bouton, rien ne fonctionnera. La télécommande elle-même ne change pas de chaîne : elle donne seulement un signal au téléviseur, à l'intérieur duquel est mis en œuvre un processus complexe de changement de chaîne. Il en va de même pour notre canard : il doit être capable de nager pour pouvoir y accéder via l'interface Swimmable. Si elle ne sait pas comment procéder, l'interface Swimmablene reliera pas les deux parties : la personne et le programme. Une personne ne pourra pas utiliser une méthode swim()pour faire Duckflotter un objet dans un programme. Vous avez maintenant vu plus clairement à quoi servent les interfaces. Une interface décrit le comportement que doivent avoir les classes qui implémentent cette interface. Le « comportement » est un ensemble de méthodes. Si nous voulons créer plusieurs messagers, le moyen le plus simple de le faire est de créer une interface Messenger. Que devrait être capable de faire n’importe quel messager ? Sous une forme simplifiée, recevez et envoyez des messages.
public interface Messenger{

     public void sendMessage();

     public void getMessage();
}
Et maintenant nous pouvons simplement créer nos classes de messagerie en implémentant cette interface. Le compilateur lui-même nous « forcera » à les implémenter dans les classes. Télégramme:
public class Telegram implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a message to Telegram!");
    }

     public void getMessage() {
         System.out.println("Reading the message in Telegram!");
     }
}
WhatsApp :
public class WhatsApp implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a WhatsApp message!");
    }

     public void getMessage() {
         System.out.println("Reading a WhatsApp message!");
     }
}
Viber :
public class Viber implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a message to Viber!");
    }

     public void getMessage() {
         System.out.println("Reading a message in Viber!");
     }
}
Quels avantages cela apporte-t-il ? Le plus important d’entre eux est le couplage lâche. Imaginez que nous concevons un programme dans lequel nous collecterons des données clients. La classe Clientdoit avoir un champ indiquant quel messager le client utilise. Sans interfaces, cela semblerait étrange :
public class Client {

    private WhatsApp whatsApp;
    private Telegram telegram;
    private Viber viber;
}
Nous avons créé trois champs, mais un client peut facilement n'avoir qu'un seul messager. Nous ne savons tout simplement pas lequel. Et pour ne pas se retrouver sans communication avec le client, il faut « pousser » toutes les options possibles dans la classe. Il s'avère qu'un ou deux d'entre eux seront toujours là nullet qu'ils ne sont pas du tout nécessaires au fonctionnement du programme. Il est préférable d'utiliser notre interface :
public class Client {

    private Messenger messenger;
}
Ceci est un exemple de « couplage lâche » ! Au lieu de spécifier une classe de messagerie spécifique dans la classe Client, nous mentionnons simplement que le client dispose d'un messager. Lequel sera déterminé au cours du programme. Mais pourquoi avons-nous besoin d’interfaces pour cela ? Pourquoi ont-ils été ajoutés à la langue ? La question est bonne et correcte ! Le même résultat peut être obtenu en utilisant l’héritage ordinaire, n’est-ce pas ? La classe Messengerest la classe parente, et Viber, Telegramet WhatsAppsont les héritiers. En effet, il est possible de le faire. Mais il y a un problème. Comme vous le savez déjà, il n’existe pas d’héritage multiple en Java. Mais il existe plusieurs implémentations d’interfaces. Une classe peut implémenter autant d’interfaces qu’elle le souhaite. Imaginez que nous ayons une classe Smartphonequi possède un champ Application- une application installée sur un smartphone.
public class Smartphone {

    private Application application;
}
L'application et le messager sont bien sûr similaires, mais ce sont quand même des choses différentes. Messenger peut être à la fois mobile et de bureau, tandis qu'Application est une application mobile. Donc, si nous utilisions l'héritage, nous ne pourrions pas ajouter d'objet Telegramà la classe Smartphone. Après tout, une classe Telegramne peut pas hériter de Applicationet de Messenger! Et nous avons déjà réussi à en hériter Messengeret à l'ajouter à la classe sous cette forme Client. Mais une classe Telegrampeut facilement implémenter les deux interfaces ! Par conséquent, dans une classe, Clientnous pouvons implémenter un objet Telegramcomme Messenger, et dans une classe Smartphonecomme Application. Voici comment procéder :
public class Telegram implements Application, Messenger {

    //...methods
}

public class Client {

    private Messenger messenger;

    public Client() {
        this.messenger = new Telegram();
    }
}


public class Smartphone {

    private Application application;

    public Smartphone() {
        this.application = new Telegram();
    }
}
Nous pouvons maintenant utiliser la classe Telegramà notre guise. Quelque part, il agira dans le rôle de Application, quelque part dans le rôle de Messenger. Vous avez probablement déjà remarqué que les méthodes dans les interfaces sont toujours « vides », c'est-à-dire qu'elles n'ont aucune implémentation. La raison en est simple : une interface décrit le comportement, pas l’implémente. « Tous les objets des classes qui implémentent l’interface Swimmabledoivent pouvoir flotter » : c’est tout ce que nous dit l’interface. Comment exactement un poisson, un canard ou un cheval nagera, c'est une question pour les classes Fish, Ducket Horse, et non pour l'interface. Tout comme changer de chaîne est la tâche d'un téléviseur. La télécommande vous donne simplement un bouton pour le faire. Cependant, Java8 a un ajout intéressant : les méthodes par défaut. Par exemple, votre interface dispose de 10 méthodes. 9 d'entre eux sont implémentés différemment dans différentes classes, mais un est implémenté de la même manière dans toutes. Auparavant, avant la sortie de Java8, les méthodes à l'intérieur des interfaces n'avaient aucune implémentation : le compilateur renvoyait immédiatement une erreur. Maintenant, vous pouvez procéder comme ceci :
public interface Swimmable {

   public default void swim() {
       System.out.println("Swim!");
   }

   public void eat();

   public void run();
}
À l'aide du mot-clé default, nous avons créé une méthode dans l'interface avec une implémentation par défaut. Nous devrons implémenter nous -mêmes les deux autres méthodes, eat()et run(), dans toutes les classes qui implémenteront Swimmable. Il n'est pas nécessaire de faire cela avec la méthode swim(): l'implémentation sera la même dans toutes les classes. À propos, vous avez rencontré des interfaces plus d'une fois dans des tâches antérieures, même si vous ne l'avez pas remarqué vous-même :) Voici un exemple évident : Pourquoi avons-nous besoin d'interfaces en Java - 2vous avez travaillé avec des interfaces Listet Set! Plus précisément, avec leurs implémentations - ArrayList, LinkedList, HashSetet autres. Le même diagramme montre un exemple lorsqu'une classe implémente plusieurs interfaces à la fois. Par exemple, LinkedListil implémente les interfaces Listet Deque(file d'attente double face). Vous connaissez également l'interface Map, ou plutôt ses implémentations - HashMap. À propos, dans ce diagramme, vous pouvez voir une fonctionnalité : les interfaces peuvent être héritées les unes des autres. L'interface SortedMapest héritée de Map, et Dequeest héritée de file d'attente Queue. Ceci est nécessaire si vous souhaitez afficher la connexion entre les interfaces, mais qu’une interface est une version étendue d’une autre. Regardons un exemple avec une interface Queue- une file d'attente. Nous n'avons pas encore parcouru les collections Queue, mais elles sont assez simples et disposées comme une file d'attente régulière dans un magasin. Vous pouvez ajouter des éléments uniquement à la fin de la file d'attente et les supprimer uniquement depuis le début. À un certain stade, les développeurs avaient besoin d'une version étendue de la file d'attente afin que des éléments puissent être ajoutés et reçus des deux côtés. C'est ainsi qu'une interface a été créée Deque: une file d'attente bidirectionnelle. Elle contient toutes les méthodes d'une file d'attente normale, car elle est le « parent » d'une file d'attente bidirectionnelle, mais de nouvelles méthodes ont été ajoutées.
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION