Tutorijali
interface tutorijal og-cs

Interface tutorijal

Interface u programiranju služi za postizanje apstrakcije. U prošlom tutorijalu smo obradili apstraktnu klasu kao još jedan način postizanja apstrakcije, pa ćemo ujedno prokomentirati razlike između ova dva načina.

Interface omogućuje da različiti objekti, koji nemaju ništa zajedničko, koriste isti kôd i ponašaju se na sličan način. Ovo je najbolje prikazati kroz primjer.

Interface u primjeru

Recimo da OG-CS razvija touchscreen tehnologiju i softver koji ga pokreće. Touchscreen je korisna i svestrana oprema, zbog čega ga koriste kompanije kao što su BASF, Deutsche Bahn i Volkswagen. U programerskom smislu touchscreen će također biti interface, jer određuje što će biti implementirano.

interface Touchscreen {
    void display();
}

U interface Touchscreen je dodana metoda display(), koja nema svoje tijelo (body). Sve metode koje nemaju svoje tijelo isključivo su tipa public i abstract, zbog čega nije potrebno navoditi te modifikatore.

Interface se nasljeđuje pomoću ključne riječi implements. Klase koje naslijede interface mogu pozvati metode koje se nalaze unutar njega, ali ne mogu pristupiti kompleksnim detaljima interfacea, čime se postiže apstrakcija. U našem primjeru, nabrojane kompanije bile bi zapravo klase koje ga koriste svaka na svoj način.

public class Basf implements Touchscreen {
    @Override
    public void display() {
    }
}
public class DeutscheBahn implements Touchscreen {
    @Override
    public void display() {
    }
}
public class Volkswagen implements Touchscreen {
    @Override
    public void display() {
    }
}

Sada kad imamo implementaciju interfacea u klasama, prilagodit ćemo njegovu upotrebu svakoj od njih. Potrebno je reći da, osim metoda, interface također može sadržavati enume i polja (fields). Dodat ćemo ih u naš primjer.

enum power {ON, OFF}
interface Touchscreen {
    String buttonA = "Button A";
    String buttonB = "Button B";
    String buttonC = "Button C";

    void display();
}

Interface Touchscreen sada ima implementiran enum te tri polja (fields). Kod interfacea sva su polja public, static i final, zbog čega ih nije potrebno upisivati (vježbe radi, svejedno ih pokušajte dodati). Evo kako će se to sada odraziti na klase koje koriste ovaj interface.

public class Basf implements Touchscreen {
    @Override
    public void display() {
        System.out.println("Choose the BASF app you want to use:");
        System.out.println(buttonA + " > R-Extruder app");
        System.out.println(buttonB + " > Publisher app");
        System.out.println(buttonC + " > Cost Steering Tool app");
        System.out.println("Important notice: Only staff with managerial roles can use the Cost Steering Tool.");
    }
}

Klasa Basf implementirala je interface Touchscreen i prilagodila ga svojim potrebama. Na touchscreenu kojeg koriste inženjeri kompanije BASF mogu se birati tri aplikacije pritiskom na odgovarajuće dugme. Primijetite kako se ta tri polja nalaze u interfaceu, ali ih ova klasa koristi za vlastite potrebe. Sada ćemo dodati interface i u ostale klase.

public class DeutscheBahn implements Touchscreen {
    @Override
    public void display() {
        System.out.println("DEUTSCHE BAHN TICKETING SYSTEM");
        System.out.println("Choose your destination: ");
        System.out.println(buttonA + " - Berlin, 74,20 €");
        System.out.println(buttonB + " - Dortmund, 45,60 €");
        System.out.println(buttonC + " - Hamburg, 115,00 €");
    }
}

Klasa DeutscheBahn je također implementirala interface Touchscreen i metodu display(), ali koristi ga na drugačiji način. Na touchscreenu kojeg koristi Deutsche Bahn mogu se kupiti karte za vlak.

public class Volkswagen implements Touchscreen {
    @Override
    public void display() {
        System.out.println("Turn the AC " + power.ON);
        System.out.println("Turn the AC " + power.OFF);
    }
}

Na touchscreenu unutar Volkswagenovog automobila uključujemo i isključujemo klima-uređaj. Iskoristili smo enum iz interfacea i prilagodili ga potrebama ove klase. U Main metodi pozvat ćemo instance ove tri klase i ispisati ih u konzoli.

public class Main {
        public static void main(String[] args) {
            Basf basfTouchscreen = new Basf();
            Volkswagen vwTouchscreen = new Volkswagen();
            DeutscheBahn dbTouchscreen = new DeutscheBahn();

            basfTouchscreen.display();
            System.out.println("-------------------------");
            vwTouchscreen.display();
            System.out.println("-------------------------");
            dbTouchscreen.display();
        }
    }

Između svake pojedine klase ispisana je isprekidana linija radi lakšeg snalaženja. Rezultat ispisa je sljedeći:

Choose the BASF app you want to use:
Button A > R-Extruder app
Button B > Publisher app
Button C > Cost Steering Tool app
Important notice: Only staff with managerial roles can use the Cost Steering Tool.
-------------------------
Turn the AC ON
Turn the AC OFF
-------------------------
DEUTSCHE BAHN TICKETING SYSTEM
Choose your destination: 
Button A - Berlin, 74,20 €
Button B - Dortmund, 45,60 €
Button C - Hamburg, 115,00 €

Kao što vidite imamo jedan interface, ali tri različite klase koje ga koriste svaka na svoj način. Interface je odredio što treba biti implementirano, ali svaka pojedina klasa je odredila način na koji to treba biti implementirano.

Implementacija više interfacea

Moguća je implementacija više od jednog interfacea unutar klase. Definirat ćemo interface UserRoles, unutar kojeg se nalaze tri polja i metoda roles().

interface UserRoles {
    String engineerRole = "Engineer";
    String supervisorRole = "Supervisor";
    String managerRole = "Manager";

    void roles();
}

Ovaj ćemo interface implementirati u klasu Basf zajedno s već implementiranim interfaceom Touchscreen.

public class Basf implements Touchscreen,UserRoles {
    @Override
    public void display() {
        System.out.println("Choose the BASF app you want to use:");
        System.out.println(buttonA + " > R-Extruder app");
        System.out.println(buttonB + " > Publisher app");
        System.out.println(buttonC + " > Cost Steering Tool app");
        System.out.println("Important notice: Only staff with managerial roles can use the Cost Steering Tool.");
    }

    @Override
    public void roles() {
        System.out.println("Logged user has a " + managerRole + " role");
    }
}

Pozvat ćemo novi interface u Main metodi.

public class Main {
        public static void main(String[] args) {
            Basf basfTouchscreen = new Basf();
            Volkswagen vwTouchscreen = new Volkswagen();
            DeutscheBahn dbTouchscreen = new DeutscheBahn();

            basfTouchscreen.display();
            basfTouchscreen.roles();
            System.out.println("-------------------------");
            vwTouchscreen.display();
            System.out.println("-------------------------");
            dbTouchscreen.display();
        }
    }

Rezultat ispisa promijenjene Main metode bit će sljedeći:

Choose the BASF app you want to use:
Button A > R-Extruder app
Button B > Publisher app
Button C > Cost Steering Tool app
Important notice: Only staff with managerial roles can use the Cost Steering Tool.
Logged user has a Manager role
-------------------------
Turn the AC ON
Turn the AC OFF
-------------------------
DEUTSCHE BAHN TICKETING SYSTEM
Choose your destination: 
Button A - Berlin, 74,20 €
Button B - Dortmund, 45,60 €
Button C - Hamburg, 115,00 €

Interface i nasljeđivanje

Interface ne može implementirati drugi interface, jer implementaciju interfacea mogu izvršiti samo klase. Međutim, u jednom od ranijih tutorijala obradili smo nasljeđivanje (inheritance) u Javi, gdje klase pomoću ključne riječi extends mogu naslijediti svojstva druge klase. Interface na isti način – pomoću ključne riječi extends – naslijeđuje drugi interface. Svrha nasljeđivanja kod interfacea je stvaranje hijerarhije između njih te nadogradnja funkcionalnosti.

enum power {ON, OFF}
interface Touchscreen extends UserRoles {
    String buttonA = "Button A";
    String buttonB = "Button B";
    String buttonC = "Button C";

    void display();
}

Klase mogu naslijediti više interfacea. U tom slučaju moraju se implementirati sve apstraktne metode iz svih interfacea koji se nasljeđuju (‘ekstendaju’). U našem primjeru sve klase su implementirale interface Touchscreen, ali samo je klasa Basf implementirala interface UserRoles. Ako interface Touchscreen zaista naslijedi interface UserRoles, to će se odraziti na klase DeutscheBahn i Volkswagen. Pokušaje samostalno saznati što će se dogoditi!

Interface i naknadne promjene u kôdu

Klasa koja implementira interface mora preuzeti sve apstraktne metode koje se nalaze unutar njega. Ako naknadno dodamo novu funkcionalnost u naš interface, to će pravilo postati problem. Primjera radi, u naš interface Touchscreen dodat ćemo metodu displayColor(String color).

enum power {ON, OFF}
interface Touchscreen {
    String buttonA = "Button A";
    String buttonB = "Button B";
    String buttonC = "Button C";

    void display();

    void displayColor(String color);
}

Zbog ove naizgled jednostavne promjene u interfaceu, sve klase koje su ga implementirale rezultirat će greškom. Da bismo ju ispravili, potrebno je dodati ovu metodu u svaku pojedinu klasu što je nepraktično, a u nekim slučajevima i nemoguće. Ovakva promjena interfacea znači neispravnu aplikaciju ili čak čitav niz aplikacija, što se ne smije dogoditi.

Kako bismo izbjegli potencijalnu katastrofu u produkciji koristit ćemo metodu koja se u Javi zove Extension metoda. Prepoznatljiva je po modifikatoru default i po tome što ima tijelo metode. Dodavanje defaultne metode u interface neće producirati grešku u klasama koje ga implementiraju.

enum power {ON, OFF}
interface Touchscreen {

    String buttonA = "Button A";
    String buttonB = "Button B";
    String buttonC = "Button C";

    void display();

    default void displayColor(String color) {
        System.out.println("The " + getClass().getName() + " has a " + color + " background");
    }
}

Sve što je sada potrebno je implementirati defaultnu metodu samo za onu klasu gdje je potrebna. Mi ćemo ju koristiti za klasu DeutscheBahn tako što ćemo ju pozvati u Main metodi. Kako bismo dali do znanja gdje se koristi defaultna metoda, koristili smo getClass().getName().

public class Main {
        public static void main(String[] args) {
            Basf basfTouchscreen = new Basf();
            Volkswagen vwTouchscreen = new Volkswagen();
            DeutscheBahn dbTouchscreen = new DeutscheBahn();

            basfTouchscreen.display();
            basfTouchscreen.roles();
            System.out.println("-------------------------");
            vwTouchscreen.display();
            System.out.println("-------------------------");
            dbTouchscreen.display();
            dbTouchscreen.displayColor("light blue");
        }
    }

Pogledajmo kako će izgledati ispis Main metode u konzoli.

Choose the BASF app you want to use:
Button A > R-Extruder app
Button B > Publisher app
Button C > Cost Steering Tool app
Important notice: Only staff with managerial roles can use the Cost Steering Tool.
Logged user has a Manager role
-------------------------
Turn the AC ON
Turn the AC OFF
-------------------------
DEUTSCHE BAHN TICKETING SYSTEM
Choose your destination: 
Button A - Berlin, 74,20 €
Button B - Dortmund, 45,60 €
Button C - Hamburg, 115,00 €
The DeutscheBahn has a light blue background

Interface i apstraktna metoda

Naučili smo kako se apstrakcija u programiranju postiže se na dva načina: pomoću apstraktne klase i pomoću Interfacea. U priloženoj tablici pokazat ćemo u čemu se ova dva pristupa razlikuju.

OpisAbstract classInterface
ključna riječextendsimplements
koristi abstract modifikatordane
koristi default modifikatorneda
koristi konstruktordane
tip metodeabstract, non-abstractabstract, static, default
final varijablefinal i non-finalfinal by default
višestruka implementacija u klasamaneda
tipovi varijablifinal, non-final, private, public, static, non-staticpublic, static, final

Autor

Marko Lubar

Ova stranica koristi kolačiće da bi poboljšalo korisničko iskustvo, više o tome možete saznajte na našoj stranici "politika privatnosti"

Politika privatnosti