CodeGym /Java Blog /Willekeurig /Waarom hebben we interfaces nodig in Java
John Squirrels
Niveau 41
San Francisco

Waarom hebben we interfaces nodig in Java

Gepubliceerd in de groep Willekeurig
Hoi! Vandaag gaan we het hebben over een belangrijk concept in Java: interfaces. Het woord komt je waarschijnlijk bekend voor. De meeste computerprogramma's en games hebben bijvoorbeeld interfaces. In brede zin is een interface een soort 'afstandsbediening' die twee op elkaar inwerkende partijen met elkaar verbindt. Een eenvoudig voorbeeld van een interface in het dagelijks leven is de afstandsbediening van een tv. Het verbindt twee objecten - een persoon en een tv - en voert verschillende taken uit: het volume hoger of lager zetten, van kanaal wisselen en de tv in- of uitschakelen. Eén partij (de persoon) moet toegang krijgen tot de interface (druk op een knop op de afstandsbediening) om de tweede partij de actie te laten uitvoeren. Bijvoorbeeld om de tv naar het volgende kanaal te laten schakelen. Bovendien hoeft de gebruiker niet U hoeft niet te weten hoe de tv is georganiseerd of hoe het kanaalwisselproces intern is geïmplementeerd. Het enige waartoe de gebruiker toegang heeft, is de interface. Het belangrijkste doel is om het gewenste resultaat te behalen. Wat heeft dit te maken met programmeren en Java? Alles :) Het maken van een interface lijkt sterk op het maken van een gewone klasse, maar dan met het woordclass geven we het woord interface aan . Laten we eens kijken naar de eenvoudigste Java-interface, zien hoe het werkt en waarom we het nodig zouden hebben:

public interface CanSwim {

     public void swim();
}
We hebben een CanSwim- interface gemaakt. Het is een beetje zoals onze afstandsbediening, maar dan met één 'knop': de swim() methode. Maar hoe gebruiken we deze afstandsbediening? Om dit te doen, moeten we een methode implementeren, namelijk onze afstandsbedieningsknop. Om een ​​interface te gebruiken, moeten sommige klassen in ons programma zijn methoden implementeren. Laten we een klasse bedenken waarvan de objecten 'kunnen zwemmen'. Een Duck- les past bijvoorbeeld :

public class Duck implements CanSwim {

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

    public static void main(String[] args) {

        Duck duck = new Duck();
        duck.swim();
    }
}
"Wat zien we hier? De klasse Duck is 'geassocieerd' met de CanSwim- interface door het sleutelwoord implements . U herinnert zich misschien dat we een soortgelijk mechanisme gebruikten om twee klassen te associëren via overerving, maar in dat geval gebruikten we het woord extends. Voor volledige duidelijkheid, we kunnen ' public class Duck implementeert CanSwim ' letterlijk vertalen als: 'The public Duck class implementeert de CanSwim -interface'. Dit betekent dat een klasse die is gekoppeld aan een interface al zijn methoden moet implementeren. Opmerking: onze Duckklasse, net als de CanSwiminterface heeft een swim()methode en bevat enige logica. Dit is een verplichte vereiste. Als we gewoon schrijvenpublic class Duck implements CanSwimzonder een swim()methode in de Duckklasse aan te maken, geeft de compiler ons een foutmelding: Duck is niet abstract en heeft geen voorrang op de abstracte methode swim() in CanSwim Waarom? Waarom gebeurt dit? Als we de fout uitleggen aan de hand van het tv-voorbeeld, zou het zijn alsof je iemand een tv-afstandsbediening geeft met een knop 'Change Channel' die niet van kanaal kan veranderen. Je kunt zo vaak op de knop drukken als je wilt, maar het werkt niet. De afstandsbediening wisselt niet zelf van kanaal: hij stuurt alleen een signaal naar de tv, die het complexe proces van het veranderen van kanaal implementeert. En zo is het ook met onze eend: hij moet kunnen zwemmen, zodat hij via de CanSwiminterface kan worden gebeld. Als het niet weet hoe, deCanSwiminterface verbindt de twee partijen niet - de persoon en het programma. De persoon kan de swim()methode niet gebruiken om binnen het programma te zwemmen Duck. Nu begrijp je beter waar interfaces voor zijn. Een interface beschrijft het gedrag dat klassen die de interface implementeren, moeten hebben. 'Gedrag' is een verzameling methoden. Als we meerdere messengers willen maken, is het het gemakkelijkst om een Messenger​​interface te maken. Wat heeft elke boodschapper nodig? Op basisniveau moeten ze berichten kunnen ontvangen en verzenden.

public interface Messenger{

     public void sendMessage();

     public void getMessage();
}
Nu kunnen we eenvoudig onze messenger-klassen maken die de bijbehorende interface implementeren. De compiler zelf zal ons 'dwingen' om ze in onze klassen te implementeren. Telegram:

public class Telegram implements Messenger {

    public void sendMessage() {

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

     public void getMessage() {
         System.out.println("Receiving a Telegram message!");
     }
}
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 Viber message!");
    }

     public void getMessage() {
         System.out.println("Receiving a Viber message!");
     }
}
Welke voordelen levert dit op? De belangrijkste daarvan is losse koppeling. Stel je voor dat we een programma ontwerpen dat klantgegevens gaat verzamelen. De Clientklasse heeft absoluut een veld nodig om aan te geven welke specifieke messenger de client gebruikt. Zonder interfaces zou dit er raar uitzien:

public class Client {

    private WhatsApp whatsApp;
    private Telegram telegram;
    private Viber viber;
}
We hebben drie velden gemaakt, maar een klant kan maar één messenger hebben. We weten alleen niet welke. We moeten dus alle mogelijkheden aan de klas toevoegen om met de klant te kunnen communiceren. Het blijkt dat een of twee van hen altijd nullvolledig onnodig zullen zijn voor het programma. Het is beter om in plaats daarvan onze interface te gebruiken:

public class Client {

    private Messenger messenger;
}
Dit is een voorbeeld van losse koppeling! In plaats van een specifieke messenger-klasse in de Clientklasse op te geven, geven we alleen aan dat de client een messenger heeft. Welke precies wordt tijdens de uitvoering van het programma bepaald. Maar waarom hebben we hiervoor interfaces nodig? Waarom zijn ze zelfs aan de taal toegevoegd? Dat is een goede vraag - en de juiste vraag! Kunnen we niet hetzelfde resultaat bereiken met gewone overerving? De Messengerklas als ouder, en Viber, Telegram, en WhatsAppals kinderen. Dat is inderdaad mogelijk. Maar er is één addertje onder het gras. Zoals u al weet, heeft Java geen meervoudige overerving. Maar er is ondersteuning voor meerdere interfaces. Een klasse kan zoveel interfaces implementeren als u wilt. Stel je voor dat we een Smartphoneklas hebben die er een heeftAppveld, dat een app vertegenwoordigt die op de smartphone is geïnstalleerd.

public class Smartphone {

    private App app;
}
Natuurlijk zijn een app en een messenger vergelijkbaar, maar het zijn nog steeds verschillende dingen. Er kunnen mobiele en desktopversies van een messenger zijn, maar de app vertegenwoordigt specifiek een mobiele app. TelegramDit is de deal: als we overerving zouden gebruiken, zouden we geen object aan de Smartphoneklasse kunnen toevoegen . De klasse kan immers Telegramniet tegelijk Appen Messenger! En we hebben het al geërfd Messengeren aan de klas toegevoegd Client. Maar de Telegramklas kan beide interfaces gemakkelijk implementeren! Dienovereenkomstig kunnen we de Clientklasse een Telegramobject geven als een Messenger, en we kunnen het aan de Smartphoneklasse geven als een App. Zo doe je dat:

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();
    }
}
Nu gebruiken we de Telegramklasse zoals we willen. Op sommige plaatsen fungeert het als een App. Op andere plaatsen fungeert het als een Messenger. Je hebt vast al gemerkt dat interfacemethodes altijd 'leeg' zijn, dwz ze hebben geen implementatie. De reden hiervoor is simpel: de interface beschrijft gedrag, maar implementeert het niet. 'Alle objecten die de CanSwiminterface implementeren, moeten kunnen zwemmen': dat is alles wat de interface ons vertelt. De specifieke manier waarop vissen, eenden en paarden zwemmen, is een vraag voor de Fish, Duck, enHorseklassen, niet de interface. Net zoals het wisselen van zender een taak is voor de tv. De afstandsbediening geeft je hiervoor gewoon een knop. Er verscheen echter een interessante toevoeging in Java 8: standaardmethoden. Uw interface heeft bijvoorbeeld 10 methoden. 9 van hen hebben verschillende implementaties in verschillende klassen, maar één is voor iedereen hetzelfde geïmplementeerd. Voorheen, vóór Java 8, hadden interfacemethodes geen enkele implementatie: de compiler gaf meteen een foutmelding. Nu kun je zoiets als dit doen:

public interface CanSwim {

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

   public void eat();

   public void run();
}
Met behulp van het defaulttrefwoord hebben we een interfacemethode gemaakt met een standaardimplementatie. We moeten onze eigen implementatie bieden voor twee andere methoden - eat()en run()- in alle klassen die CanSwim. Met de methode hoeven we dit niet te doen swim(): de implementatie zal in elke klas hetzelfde zijn. Trouwens, je bent al interfaces tegengekomen in eerdere taken, ook al was het je niet opgevallen :) Hier is een levendig voorbeeld: Waarom interfaces nodig zijn in Java - 2je hebt met de interfaces Listen gewerkt! SetMeer precies, je hebt met hun implementaties gewerkt - ArrayList, LinkedList, HashSet, enz. Hetzelfde diagram geeft duidelijk een voorbeeld waarbij één klasse meerdere interfaces tegelijkertijd implementeert. LinkedListImplementeert bijvoorbeeld de ListenDeque(dubbele wachtrij) interfaces. Je bent bekend met de Mapinterface, of beter gezegd, met de HashMapimplementatie ervan. Overigens illustreert dit diagram een ​​kenmerk: interfaces kunnen andere interfaces overnemen. De SortedMapinterface erft Map, terwijl Dequeerft Queue. Dit is nodig als je de relatie tussen interfaces wilt laten zien, waarbij de ene interface een uitgebreide versie is van een andere. Laten we eens kijken naar een voorbeeld met de Queueinterface. We hebben nog niet beoordeeldQueues, maar het is vrij eenvoudig en werkt als een gewone wachtrij of rij in een winkel. U kunt alleen items toevoegen aan het einde van de wachtrij en u kunt ze alleen vanaf het begin pakken. Op een gegeven moment hadden ontwikkelaars een verbeterde versie van de wachtrij nodig om items aan beide uiteinden toe te voegen en te verwijderen. Dus creëerden ze een Dequeinterface, een wachtrij met twee uiteinden. Het heeft alle methoden van een gewone wachtrij. Het is tenslotte de ouder van de wachtrij met twee uiteinden, maar het voegt ook nieuwe methoden toe.
Opmerkingen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION