Mire jó az "implements"

Fórumok

A következő példát találtam a Java dokumentációban:


public interface Colorable {
   void setColor(int color);
   int getColor();
}
public enum Finish {MATTE, GLOSSY}
public interface Paintable extends Colorable {
   void setFinish(Finish finish);
   Finish getFinish();
}
class Point { int x, y; }
class ColoredPoint extends Point implements Colorable {
   int color;
   public void setColor(int color) { this.color = color; }
   public int getColor() { return color; }
}
class PaintedPoint extends ColoredPoint implements Paintable
{
   Finish finish;
   public void setFinish(Finish finish) {
      this.finish = finish;
   }
   public Finish getFinish() { return finish; }
}

A kérdésem: Mire jó ez az "implementálgatás"? Pl. a ColoredPoint osztályba akkor is létrehozhatnánk a setColor() és getColor() tagfüggvényeket, ha nem implementálnánk a Colorable osztályt. Nem értem miért "kell" (miért érdemes) külön interface osztályt erre létrehozni.

Hozzászólások

Azert, mert a Java nem tamogatja pl a tobbszoros oroklodest, viszont egy osztaly implementalhat akar tobb interfacet is.

Igy lehet egy X interfaced, meg egy Y, es lehet egy Z osztalyod, amely egyben X is es Y is.

Azért jó, mert egy interface implementáltságát egy osztályon az instanceof kulcsszóval lekérdezheted runtime.

Tehát kapsz egy akármilyen típusú objektumot, mert mindegy milyen, de lényeg, hogy legyen benne egy függvény. Ekkor egy interface absztrahálja a függvénydefiníciót, majd a függvény meghívása előtt:
if(anObj instanceof ISzarAzÉlet)
{blabla;}

Ha igaz a kifejezés, akkor a tökmindegy osztályt példányosító ojjektumnak van az interface által megadott függvénye, ha hamis, akkor nincs.
dontflamemeplz://Így a többszörös öröklődés hiányát kikerülve lehet kvázi többszörösen örököltetni :D

Pl akkor jó, amikor van egy algoritmusod(mindjuk egy mestint kereső), s annak megadhatsz mindenféle ojjektumokat. Ekkor a midnenféle ojjektum egyetlen kikötése, hogy a kereső által megadott interface-t implementálja, ezzel biztosítva a keresőnek kellő getterek, s egyéb szirszarok jelenlétét.

--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.

ez azért jó (pl. ebben az esetben) mert ha van egy Colorable típusu változód, az tartalmazhat ColoredPoint-ot, de akár egy másik objektumot is ami szintén megvalósítja azt az interfészt.

Ez az interfész dolog ilyen tervezési segítség, ahol csak absztrakt definíciókat adunk meg, hogyan érhetjük el az objektumunkat (mely metódusok segítségével), és ezután több különböző megvalósítást is készíthetünk az interfészhez.
Ez azért jó nekünk mert például írunk egy (pl.) szövegszerkesztő programot ami mondjuk többfajta helyesírásellenőrzőt is támogat, akkor 1x elkészítjük az interfészt (gondolva rá hogy mire lehet szükségünk a jövőben) és több különböző megvalósítást is létrehozhatunk (pl. hunspell/aspell/myspell/saját...) anélkül hogy ahol felhasználtuk az interfészünket ott már nem kell sehol matatni többet, illetve futásidőben is változtathatjuk a helyesírásellenűrzés fajtáját...

lehet hogy hülyén fogalmaztam, de ilyesmire jó ez a dolog

kedz

ui. lehet hogy nem jót írtam, annyira nem értek a java-hoz...

Erre nagyon rátapintottál!
Jelen pillanatban tényleg egy szövegszerkesztőn dolgozom, amibe be szeretném implementálni a Hunspell helyesírás elemzőt.

A Jazzy nevű helyesírás ellenőrző egyik példaprogramjából indulok ki, amelyben meg van valósítva az automatikus helyesírás ellenőrzés (piros hullámvonallal aláhúzza a hibás szót). Ugyanakkor szép formázott szövegeket lehet benne szerkeszteni. Bár nagyon egyszerű, és rengeteg fejleszteni való lesz rajta az én speciális alkalmazásomhoz.

Na és ha egy interface egy másik interface leszármazottja, akkor örökli az ős interface-ben már deklarált tagfüggvényeit?

Pl:


import java.util.EventListener;

public interface SpellCheckListener extends EventListener {

  public void spellingError(SpellCheckEvent event);
  
} // end of interface

Ekkor az SpellCheckListener már két függvénnyel rendelkezik? A handleEvent() és spellingError() fügvényekkel?

További kérdés: Muszáj egy az interface-t implementáló osztálynak az összes implementált tagfüggvényt definiálni (meghatározni)?

Köszönöm a hozzászólásokat. Most már világosabb a kép.

Írjatok még, ha van valami fontos észrevételetek!

Arról volt szó, hogy egy olyan interfész implementálása esetén, amely egy ős interfész leszármazottja, definiálni kell az ős interfész és a leszármazott interfész metódusait is.

Ennek ellentmondó megvalósítást találtam a Jazzy forráskódjában:


// Ezt az interfészt már korábban bemutattam:
import java.util.EventListener;

public interface SpellCheckListener extends EventListener {

  public void spellingError(SpellCheckEvent event);
  
} // end of interface

//-------------------------------------------------------
// Ugyanakkor:

public class JTextComponentSpellChecker implements SpellCheckListener {

  // Egyéb tagfüggvények.  

  public void spellingError(SpellCheckEvent event) {
    // valami kód.
  }

  // Nincs definiálva a handleEvent() metódus!!!!!
}

A program működik, és nincs is fordítási hiba. Tehát nem kell minden tagfüggvényt definiálni abban az osztályban, amely implementál egy interfészt?
Vagy lehet, hogy a standard handleEvent() metódus az EventListener interfészben nem csak deklarálva van, hanem valami kód is van hozzá megadva, így nem szükséges minden áron megadni a JTextComponentSpellChecker osztályban?

Interfészben biztos, hogy semmilyen kód nincs "megadva", attól interfész.

Valóban, minden metódust ki kell fejteni, beleértve mindent, ami az implementált interfészekben definiálva van. Kivéve absztrakt osztály esetén.

Viszont én nem látok semmilyen handleEvent() -et az EventListenerben: http://java.sun.com/javase/6/docs/api/java/util/EventListener.html

Igazad van! Kösz!

Valamiért a EventListener-t néztem a org.w3c.dom.events nevű package-ban. És meg voltam győződve, hogy az az EventListener, ami az enyém. (Ezt jól elnéztem!)

Ugyanakkor érdekes, hogy ez az EventListener egyetlen tagfüggvényt sem tartalmaz. Csak azért hozták létre, hogy valami nevet adjanak a dolognak.
De mégis nagyon sok osztályba be lett implementálva. Nem értem miféle funkciót láthat el egy osztályban, ha egyetlen tagfüggvénye sincs. Vajon csak annyit, hogy egy későbbi alkalmazás ezzel a névvel összefoghatja (utalhat) az összes Listenerre?

"Arról volt szó, hogy egy olyan interfész implementálása esetén, amely egy ős interfész leszármazottja, definiálni kell az ős interfész és a leszármazott interfész metódusait is. "

Ehhez a mondathoz meg annyit, hogy nem az "ős interfész" plusz a "leszármazott interfész" metódusait fejted ki, hanem azt, amit az éppen implementált interfész definiál. Az, hogy ez az interfész mit honnan örököl, és mit tesz hozzá saját maga, nem számít. Ez nagyon fontos, erről szól az egész.

Szerk. javítom magamat. Természetesen számít, egy másik időpontban rendkívül hasznos lehet, hogy a classod ami pl egy TableModelListener, az egyben EventListener is (pont hülye példa). De attól még nem hierarchikusan fejted ki a dolgokat.

Mivel a Java erősen típusos nyelv, viszont csak az egyszeres öröklődés támogatott, ezért szükség van az interface-ekre. Gondolj bele, hogy egy függvényt, ami egy java.util.List-et kap paraméterül, interface-ek nélkül külön kellene implementálni minden List típusra (ArrayList-re, LinkedList-re, stb.), hiszen meg kell mondani a paraméter típusát. Az említett osztályok add() függvényének implementációja lényegesen eltér egymástól, gyakorlatilag semmilyen közös kódót nem tudnak használni, a viselkedésük viszont teljesen megegyezik (kivéve a hatékonyságukat). Interface-ek nélkül szükség lenne egy közös ősosztályra, ami deklarálja az add() függvényt. Viszont mivel az ősosztálynak fogalma sem lehet a különböző megvalósítási lehetőségekről, ez a függvény nem tartalmaz egy utasítást sem. Így viszont nem teljesíti az add() által elvártakat, tehát ki kell kényszeríteni annak definiálását. Ennek egyik módja, ha az osztályban függvénytörzs nélkül az "abstract" kulcsszóval deklaráljuk a függvényt.
Az abstract osztályok hasonlóak az interface-ekhez annyiban, hogy azok is egy interfészt (felületet) deklarálnak, viszont az implementáló osztályok által használható utility-szerű függvények implementálva vannak, vagy más esetekben nem engedve az implementáló osztályok számára bizonyos viselkedés felülírását (persze minden megkerülhető, de a lényeg a szándék világos megfogalmazása).
Egy mondatban: az interface lényege hogy az interface által megfogalmazott követelményeknek az implementáló osztályok megfelelnek, és ebben bízhatnak az őket felhasználó programrészek (lásd java.util.List metódusai pl.).

Eddig is muszáj volt használnom a különböző interfészeket a programjaimban, csak eleddig nem voltam tisztában, mi is a pontos (és fontos) szerepük az osztályaimban.

Jó, hogy kitárgyaltuk. Köszönöm a magyarázatokat.