Heb je misschien een stukje code waarin naar voren komt dat een interface in die betreffende situatie handiger is dan een superklasse?
Een stukje code heb ik niet echt. Interfaces worden meestal enkel gebruikt in de iets grotere projecten en ik denk niet dat je daardoor direct een stuk wijzer wordt.
Zoals ik het nu zie, krijg ik de indruk dat je beter maar helemaal geen gebruik meer moet maken van een superklasse, maar beter om voortaan van een interface gebruik te maken. Hoewel, stel dat een methode 'Start()' voor alle subklasses op dezelfde manier geimplementeerd wordt, dan is een superklasse weer handig, want om nou hetzelfde stukje code (nl. die van de methode 'Start()') bij alle subklasses te plaatsen is ook een beetje overdreven. Maar in alle andere gevallen kun je dus beter gebruik maken van interfaces?
Een superklasse is enkel handig zoals je zelf aanhaalt wanneer je bepaalde functies kan implementeren die alle afgeleide klassen zeker ook zullen hebben en die altijd op dezelfde manier geprogrammeerd zal zijn. Echter komt dit niet zo heel vaak voor. Vaak kom je te zitten met klassen die allemaal wel op mekaar gelijken, maar niet op dezelfde manier werken. Op dat moment kan je geen superklasse meer maken die op zichzelf kan bestaan.
Misschien toch nog een voorbeeld waar een superklasse niet meer zinnig is:
Klasse voertuig:
Een voertuig heeft altijd een plaats voor een persoon te vervoeren.
Het moet kunnen stoppen en starten.
Het heeft een bepaalde aandrijvingskracht nodig.
Natuurlijk is een voertuig niet iets dat op zichzelf kan bestaan. Als ik jou nu vraag om een voertuig te maken in het echte leven zal jij misschien een fiets maken en een ander persoon een go-cart en nog een ander persoon een auto. Het voertuig zelf is niet iets dat op zichzelf kan bestaan, het moet altijd verder gespecifieerd worden. Echter weet iedereen perfect dat een voertuig bepaalde eisen heeft zoals die hierboven staat. Je zou nu kunnen stellen dat voertuig een interface is.
Code: Selecteer alles
Interface voertuig {
void Start();
void Stop();
boolean persoonAanwezig();
}
Je kan nu gaan zeggen dat zowel een go-cart als een fiets berusten op hetzelfde principe qua aandrijving. Beide hebben tandwielen nodig en een ketting waaraan pedalen vasthangen. Beiden zullen dus dezelfde soort Start() methode kennen. Je kan dus een superklasse maken tandwielAangedreven.
Code: Selecteer alles
Class tandwielAangedreven implements voertuig {
void Start() {
// ga op de trappers staan en draai ze rond
}
}
Stel nu dat je van voertuig een bovenklasse had gemaakt dan hadden we nu een probleem met de auto. Een auto is ook een voertuig, maar kent een heel andere startmethode. Nu kon je wel de auto een aparte start methode meegeven maar elke keer je de auto zou willen starten dan zou je het object als 'Auto' en niet als 'Voertuig' moeten aanspreken. Wanneer je bv een tabel van voertuigen hebt zou je elke keer moeten checken of je een auto hebt of iets anders en als je een auto had zou je deze elke keer moeten casten. Je ziet dus dat je al in de knoop begint te geraken omdat een auto op een totaal andere manier de startfunctie moet programmeren.
Nu we de interface hebben gemaakt kunnen we perfect een tabel van voertuigen aanmaken en van alle elementen de start() methode oproepen zonder ons zorgen te hoeven maken of een bepaalde object een eigen specifieke start methode heeft.
Ik hoop dat het nu duidelijk is wanneer je een interface gebruikt en wanneer een bovenklasse.
Hier nog een kort schema van de mogelijke indeling:
Code: Selecteer alles
Voertuig (interface)
/
\
tandwielAangedreven (klasse) Auto (klasse)
/
\
Fiets (klasse) Go-cart (klasse)