Gyakorlati alapok III.
Az interfész alapszintű működése egy példán keresztül
Ismételjük meg az előző fejezet egyik legfontosabb megállapítását:
Kódredundancia helyett az osztályhierarchiában több, funkcionalitásában, működésében különböző (azaz különböző tulajdonságú) osztályt fogunk találni, amelyek között egyfajta hídként az interfész lehetőségét használhatjuk fel, ha 2 különböző osztály között közös tulajdonságokat akarunk kialakítani.
Tehát az interfész alapértelmezésben híd, másképpen fogalmazva a közös
tulajdonság (vagy közös tulajdonságok csoportja) a különböző tulajdonságú
osztályok között. Erre fogunk látni az alábbiakban 1 viszonylag egyszerű példát.
Mindenekelőtt azonban hangsúlyozni szeretném, hogy a példa alaphelyzete
meglehetősen elméleti. Szinte egészen bizonyos, hogy nem az alábbiak szerint
kell az osztályok funkcióit kialakítani, de ne felejtsük el, hogy mi most
csupán érthető példával igyekszünk megbirkózni, nem pedig kísérletet teszünk
1 osztályhierarchia kialakítására.
Új, Kor névvel ellátott projekt alkotása után a következő programelemeket alkotjuk meg:
-
KorTeruletOsszegzo osztály - nevéből adódóan sok kör területét adja össze (összegzi),
-
KorTeruletAtlagolo osztály - nevéből adódóan sok kör területéből számítja ki a területi átlagot,
-
IKorTulajdonsagok interfész,
-
Main - az osztályok példányosításának, futtatásának helye.
Nem nehéz észrevennünk a KorTeruletOsszegzo és KorTeruletAtlagolo osztályok közös tulajdonságait. Mindkettő körrel és annak területével készül dolgozni, tehát ezen programelemeket interfész segítségével fogjuk implementálni:
-
a PI értéke,
-
a kör területszámításának metódusa,
-
nem közvetlenül tartozik ide, de most idevehetjük a körök számát is.
Az interfész konstansokat és
metódusfejeket definiál azon célból, hogy a későbbiekben azt az implementáló
osztályban teljes egészében kidolgozzuk. Sőt, interfész deklarálása esetén a
metódusokat ott egyenesen kötelező kidolgoznunk, másként fordítási hibát
kapunk.
Először nézzük meg az interfész implementációját, amelyet utána szét is boncolunk. A projekt létrehozása után, a src mappában, automatizált körülmények között tudjuk létrehozni az interfészt:
Az interfész kötelezően public, hiszen nincs értelme felhasználni, ha nem is látható (azaz elveszíti híd-jellegét). Ha nem adjuk meg a public hozzáférés-módosítást, akkor láthatósága csomagszintű.
Az interfész alapértelmezésben abstract, azaz nem példányosítható. Igazából nem is tudjuk ezt megtenni, mert nem működőképes kód, csak "emlékeztetőket" tartalmaz arra vonatkozóan, hogy mit is kell majd kidolgoznunk az implementáló osztályban. Az emlékeztetők pedig azok a metódusfejek, amelyeknek az interfészen belül nincs műveleti blokkjuk, a mi esetünkben például:
double korTerulet(int sugar, double PI);
A metódusfej tehát leginkább a művelet szignatúrájához hasonlít.
Ha az interfész konstansokat is tartalmaz, akkor a konstansok módosításai -akár kitesszük, akár nem-, public, static, final, ezt nem tudjuk befolyásolni.
Nézzük meg az interfész implementációját:
import
java.math.*;
public interface IKorTulajdonsagok {
double PI = Math.PI;
int korSzam = 10;
double korTerulet(int sugar, double PI);
}
Nem oly szigorú, de sok helyen elvárt névadási konvenció az interfészek kezdőneveit nagy I betűvel kezdeni, itt: IKorTulajdonsagok.
double PI = Math.PI;
Nem túl elegáns egy már meglévő konstans értéket (Math.PI) másikba átvezetni (double PI). Ezt most azért tettem így, hogy a későbbiekben lássuk, milyen egyszerűen hivatkozhatunk az általunk kreált konstansokra az interfész felhasználásával.
int korSzam = 10;
Ez egy másik konstans, bár nem közvetlenül tartozik ide, inkább csak a példa kedvéért tettük konstanssá.
double korTerulet(int sugar, double PI);
A metódusfej, mint "emlékeztető" arra vonatkozóan, hogy mit kell a későbbiekben kidolgoznunk az implementáló osztályban.
Ezután fel kell építenünk az implementáló osztály(ok)at. Az interfészt az implementáló osztályba az implements szóval vezetjük be. Először nézzük meg a KorTeruletOsszegzo osztályt:
public class KorTeruletOsszegzo implements IKorTulajdonsagok{
KorTeruletOsszegzo(){
System.out.println(osszegzo());
};
@Override
public double korTerulet(int sugar, double PI){
return (sugar * sugar) * PI;
}
public double osszegzo(){
double korTeruletOsszeg = 0;
for(int i = 1; i <= korSzam; i++){
int sugar = i;
korTeruletOsszeg += korTerulet(sugar,
PI);
System.out.println(sugar + " egység
sugarú kör területe: " + korTerulet(sugar, PI));
}
System.out.print("Körterületek összege: " + korTeruletOsszeg);
return korTeruletOsszeg;
}
}
Az @Override intelligens annotáció jelzi, hogy kötelező kidolgoznunk a metódust és hibaüzenettel addig nem is hagy minket békén, ameddig ezt nem tesszük meg.
Ugyanezen lépéseket kell megtennünk a KorTeruletAtlagolo osztállyal kapcsolatban is:
public class KorTeruletAtlagolo implements IKorTulajdonsagok{
KorTeruletAtlagolo(){
System.out.println(atlagolo());
};
@Override
public double korTerulet(int sugar, double PI){
return (sugar * sugar) * PI;
}
public double atlagolo(){
double korTeruletOsszeg = 0;
for(int i = 1; i <= korSzam; i++){
int sugar = i;
korTeruletOsszeg += korTerulet(sugar,
PI);
System.out.println(sugar + " egység
sugarú kör területe: " + korTerulet(sugar, PI));
}
System.out.print("Körterületek átlaga: " + korTeruletOsszeg /
korSzam);
return korTeruletOsszeg / korSzam;
}
}
A Main osztályban a fenti 2 osztály példányosítása a konstruktor függvényeik rafinált felülírásával valósul meg, amely által a kódfuttatás egyszerűbbé válik:
public class Main {
public static void main(String[] args) {
new KorTeruletOsszegzo();
System.out.println();
new KorTeruletAtlagolo();
}
}
Végeredmény:
1 egység sugarú kör területe: 3.141592653589793
2 egység sugarú kör területe: 12.566370614359172
3 egység sugarú kör területe: 28.274333882308138
4 egység sugarú kör területe: 50.26548245743669
5 egység sugarú kör területe: 78.53981633974483
6 egység sugarú kör területe: 113.09733552923255
7 egység sugarú kör területe: 153.93804002589985
8 egység sugarú kör területe: 201.06192982974676
9 egység sugarú kör területe: 254.46900494077323
10 egység sugarú kör területe: 314.1592653589793
Körterületek összege: 1209.51317163207051209.5131716320705
1 egység sugarú kör területe: 3.141592653589793
2 egység sugarú kör területe: 12.566370614359172
3 egység sugarú kör területe: 28.274333882308138
4 egység sugarú kör területe: 50.26548245743669
5 egység sugarú kör területe: 78.53981633974483
6 egység sugarú kör területe: 113.09733552923255
7 egység sugarú kör területe: 153.93804002589985
8 egység sugarú kör területe: 201.06192982974676
9 egység sugarú kör területe: 254.46900494077323
10 egység sugarú kör területe: 314.1592653589793
Körterületek átlaga: 120.95131716320705120.95131716320705
Ne felejtsük el pontosan megalkotni és beállítani a fenti osztályok forráskódjait! A hibamentes futtatáshoz az alábbi szerkezetet kell kialakítanunk a projekt src mappájában: