Interface u programiranju
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.
Pregled sadržaja
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.
Opis | Abstract class | Interface |
ključna riječ | extends | implements |
koristi abstract modifikator | da | ne |
koristi default modifikator | ne | da |
koristi konstruktor | da | ne |
tip metode | abstract, non-abstract | abstract, static, default |
final varijable | final i non-final | final by default |
višestruka implementacija u klasama | ne | da |
tipovi varijabli | final, non-final, private, public, static, non-static | public, static, final |