CodeGym /Java blog /Véletlen /Miért van szükségünk interfészekre a Java nyelven?
John Squirrels
Szint
San Francisco

Miért van szükségünk interfészekre a Java nyelven?

Megjelent a csoportban
Szia! Ma a Java egyik fontos fogalmáról fogunk beszélni: az interfészekrõl. A szó valószínűleg ismerős számodra. Például a legtöbb számítógépes program és játék rendelkezik interfésszel. Tágabb értelemben az interfész egyfajta „távirányító”, amely két egymással együttműködő felet köt össze. Egy egyszerű példa a mindennapi élet interfészére a TV távirányítója. Két objektumot – egy személyt és egy tévét – köt össze, és különböző feladatokat hajt végre: fel- vagy lehalkítja a hangerőt, csatornát vált, és be- vagy kikapcsolja a TV-t. Az egyik félnek (a személynek) hozzá kell férnie az interfészhez (nyomjon meg egy gombot a távirányítón), hogy a másik fél végrehajtsa a műveletet. Például, hogy a TV-t a következő csatornára váltsa. Mi több, a felhasználó nem t tudnia kell, hogyan van felszerelve a TV, vagy hogyan valósul meg a csatornaváltás folyamata belülről. Az egyetlen dolog, amihez a felhasználó hozzáfér, az a felület. A fő cél a kívánt eredmény elérése. Mi köze ennek a programozáshoz és a Java-hoz? Mindent :) A felület létrehozása nagyon hasonlít egy normál osztály létrehozásához, de helyette a szót használjukosztályban a felület szót jelöljük . Nézzük meg a legegyszerűbb Java felületet, nézzük meg, hogyan működik, és miért lenne szükségünk rá:

public interface CanSwim {

     public void swim();
}
Létrehoztunk egy CanSwim felületet. Kicsit olyan, mint a távirányítónk, de egyetlen 'gombbal': a swim() metódussal. De hogyan használjuk ezt a távirányítót? Ehhez meg kell valósítanunk egy módszert, vagyis a távirányító gombunkat. Az interfész használatához programunk egyes osztályainak implementálniuk kell a metódusait. Találjunk ki egy osztályt, amelynek objektumai „tudnak úszni”. Például egy kacsa osztály megfelel:

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();
    }
}
"Mit látunk itt? A Duck osztályt az implements kulcsszó "társítja" a CanSwim felülethez . Emlékezhetsz arra, hogy hasonló mechanizmust használtunk két osztály társítására öröklődés útján, de ebben az esetben az extends szót használtuk. teljes egyértelműség, a ' public class Duck implements CanSwim ' szó szerint így fordítható : 'A nyilvános Duck osztály implementálja a CanSwim interfészt'. Ez azt jelenti, hogy egy interfészhez társított osztálynak az összes metódusát meg kell valósítania. Megjegyzés: a mi osztályunk, mint ahogy az interfész, van egy metódusa, és van benne némi logika.Ez egy kötelező követelmény.Ha csak írunkDuckCanSwimswim()public class Duck implements CanSwimmetódus létrehozása nélkül swim()az Duckosztályban a fordító hibát jelez: A Duck nem absztrakt, és nem írja felül az absztrakt swim() metódust a CanSwim-ben Miért? Miért történik ez? Ha a TV-példával magyarázzuk el a hibát, az olyan lenne, mintha valaki kezébe adna egy TV távirányítót egy „csatornaváltás” gombbal, amely nem tud csatornát váltani. Nyomhatod a gombot, ahányszor csak akarod, de nem megy. A távirányító önmagában nem vált csatornát: csak jelet küld a TV-nek, ami a csatornaváltás összetett folyamatát valósítja meg. Így van ez a mi kacsánkkal is: tudnia kell úszni, hogy a CanSwimfelület segítségével hívható legyen. Ha nem tudja hogyan, aCanSwiminterfész nem köti össze a két felet – a személyt és a programot. A személy nem fogja tudni használni a swim()módszert a programon belüli úszásra Duck. Most már világosabban megérti, mire valók az interfészek. Egy interfész leírja azt a viselkedést, amellyel az interfészt megvalósító osztályoknak rendelkezniük kell. A „viselkedés” módszerek gyűjteménye. Ha több messengert szeretnénk létrehozni, akkor a legegyszerűbb egy felület létrehozása Messenger. Mire van szüksége minden hírnöknek? Alapszinten képesnek kell lenniük üzenetek fogadására és küldésére.

public interface Messenger{

     public void sendMessage();

     public void getMessage();
}
Most egyszerűen létrehozhatjuk messenger osztályainkat, amelyek megvalósítják a megfelelő felületet. A fordító maga „kényszerít” bennünket, hogy implementáljuk ezeket az osztályainkban. Távirat:

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!");
     }
}
Milyen előnyökkel jár ez? Ezek közül a legfontosabb a laza tengelykapcsoló. Képzelje el, hogy egy olyan programot tervezünk, amely összegyűjti az ügyféladatokat. Az Clientosztálynak feltétlenül szüksége van egy mezőre, amely jelzi, hogy a kliens melyik üzenetküldőt használja. Interfészek nélkül ez furcsán nézne ki:

public class Client {

    private WhatsApp whatsApp;
    private Telegram telegram;
    private Viber viber;
}
Három mezőt hoztunk létre, de egy kliensnek csak egy messengere lehet. Csak azt nem tudjuk, melyik. Tehát minden lehetőséget hozzá kell adnunk az osztályhoz, hogy kommunikálni tudjunk az ügyféllel. Kiderült, hogy egy vagy kettő közülük mindig is null, teljesen szükségtelen a programnak. Inkább a mi felületünket érdemes használni:

public class Client {

    private Messenger messenger;
}
Ez egy példa a laza kapcsolásra! Ahelyett, hogy egy adott messenger osztályt adnánk meg az osztályban Client, csak azt jelezzük, hogy az ügyfélnek van messengere. Hogy pontosan melyiket, az a program futása során kerül meghatározásra. De miért kellenek ehhez interfészek? Miért adták hozzá a nyelvhez? Ez egy jó kérdés – és a helyes kérdés! Nem érhetjük el ugyanezt az eredményt közönséges örökléssel? Az Messengerosztály mint szülő, és Viber, Telegram, és WhatsAppmint gyerekek. Valóban, ez lehetséges. De van egy bökkenő. Mint már tudja, a Java-nak nincs többszörös öröklődése. De több interfész is támogatott. Egy osztály annyi interfészt implementálhat, amennyit csak akar. Képzeljük el, hogy van egy Smartphoneosztályunk, amelynek vanAppmező, amely az okostelefonra telepített alkalmazást jelöli.

public class Smartphone {

    private App app;
}
Természetesen az alkalmazás és a messenger hasonló, de mégis különböző dolgok. A messengernek lehetnek mobil és asztali verziói is, de az App kifejezetten egy mobilalkalmazást jelent. Itt van az üzlet – ha öröklést használnánk, nem tudnánk objektumot hozzáadni Telegramaz Smartphoneosztályhoz. Hiszen az Telegramosztály nem örökölheti egyszerre Appés Messenger! És már örököltük, Messengerés hozzáadtuk az osztályhoz Client. De az Telegramosztály mindkét felületet könnyen megvalósíthatja! ClientEnnek megfelelően az osztálynak egy Telegramobjektumot adhatunk Messenger, és megadhatjuk az Smartphoneosztálynak mintként App. Íme, hogyan kell ezt megtenni:

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();
    }
}
Most úgy használjuk az Telegramosztályt, ahogy akarjuk. Egyes helyeken úgy működik, mint egy App. Más helyeken úgy működik, mint a Messenger. Biztosan észrevette már, hogy az interfész metódusok mindig „üresek”, azaz nincs implementációjuk. Ennek egyszerű az oka: a felület leírja a viselkedést, de nem valósítja meg. „Minden objektumnak, amely megvalósítja az CanSwiminterfészt, tudnia kell úszni”: ennyit mond nekünk az interfész. A halak, kacsák és lovak úszásának konkrét módja a Fish, Duck, és aHorseosztályok, nem a felület. Ahogy a csatornaváltás is a tévé feladata. A távirányító egyszerűen ad egy gombot ehhez. A Java 8-ban azonban megjelent egy érdekes kiegészítés – az alapértelmezett módszerek. Például az Ön interfésze 10 metódussal rendelkezik. Közülük 9 különböző implementációval rendelkezik különböző osztályokban, de egy mindegyikre ugyanaz. Korábban, a Java 8 előtt az interfész metódusoknak nem volt implementációja: a fordító azonnal hibát adott. Most valami ilyesmit tehet:

public interface CanSwim {

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

   public void eat();

   public void run();
}
A defaultkulcsszó használatával létrehoztunk egy interfész metódust alapértelmezett megvalósítással. Saját implementációt kell biztosítanunk két másik metódushoz – eat()és run()– minden olyan osztályban, amely megvalósítja CanSwima . A metódussal ezt nem kell megtennünk swim(): a megvalósítás minden osztályban ugyanaz lesz. Egyébként a múltbeli feladatokban már találkoztál interfészekkel, még ha nem is vetted észre :) Itt egy szemléletes példa: Miért szükségesek interfészek a Java-ban - 2Dolgoztál a Listés Setfelületekkel! Pontosabban, az implementációikkal dolgozott – ArrayList, LinkedList, HashSet, stb. Ugyanez a diagram egyértelműen példát mutat arra, amikor egy osztály több interfészt valósít meg egyszerre. Például LinkedListmegvalósítja az ListésDeque(kétvégű sor) interfészek. Ismeri a Mapfelületet, vagy inkább annak HashMapmegvalósítását. Ez a diagram egyébként egy jellemzőt szemléltet: az interfészek örökölhetnek más interfészt. Az SortedMapinterfész örökli Map, míg Dequeörökli Queue. Erre akkor van szükség, ha meg akarjuk mutatni az interfészek közötti kapcsolatot, ahol az egyik interfész egy másik bővített változata. Nézzünk egy példát az interfészre Queue. Még nem vizsgáltuk átQueues, de meglehetősen egyszerű, és úgy működik, mint egy szokásos sorban állás az üzletben. Csak a sor végére adhat hozzá elemeket, és csak az elejétől veheti át őket. Valamikor a fejlesztőknek szükségük volt a várólista továbbfejlesztett verziójára, hogy mindkét végén hozzáadhassanak és átvehessék az elemeket. Így létrehoztak egy Dequeinterfészt, ami egy kétvégű sor. A közönséges sor összes metódusával rendelkezik. Végül is ez a kétvégű sor szülője, de új metódusokat is hozzáad.
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION