Interfacen kræver endda at man implementerer alle dens metoder hvis man vil bruge den.. hvorfor?
Pointen er at abstrahere væk fra en specifik klasse, en bestemt måde at gøre det på, fra det du faktisk ønsker muligt. Hvis du giver mig et objekt som implementerer InterfaceTest, så forventer jeg at kunne kalde både setSize og getSize. Det er den abstraktion som InterfaceTest giver mig og kompileren håndhæver den. Jeg kan ikke vide at kun halvdelen er implementeret og hvis jeg kunne så kan jeg højst sandsynligvis ikke bruge den siden man typisk har brug for alle Interface's metoder.
Pointen er at undgå kobling samt at få mere abstraktion. Du har du et meget lille eksempel, men i større projekter kan det have stor betydning. I din main skriver du TestInterface1. Forestil dig nu at du gerne vil implementere setSize og getSize på en anden måde. Så skulle du enten rette i TestInterface1 klassen (som måske stadig skal bruges som den er et andet sted) eller lave en ny klasse med samme metoder og ændre det alle de steder der bruges TestInterface1.
For et software bibliotek ville dette måske være endnu mere problematisk, siden folk måske har kompileret kode opad det gamle navn.
Til 1 interface kan du have N klasser. Ved at bruge klassenavnene skal du ændre flere steder hvis du ændrer på koden, med et interface skal du kun ændre det de steder du instantierer.
Det eksempel du kommer med er heller ikke så god til at vise fordelene. Normalt beskriver et Interface's metoder adfærd, men ikke hvordan det skal gøres. getSize og setSize, kan snævert beskrives som adfærd, og det 'lækker' detaljer om hvordan en klasse skal implementeres i stedet for hvorfor. Til en datastruktur kan getSize måske gå an men ikke setSize.
Her er et eksempel som jeg mener bedre viser styrkerne:
- public Interface GameObject {
- public void update();
- public void render(Graphics g);
- }
-
- public class Man implements GameObject {
- //...... Andre metoder, og instansvariabler
- //Som eatFood og move
- public void update() {
- int food = World.getFoodInPos(this.getPos());
- eatFood();
- move();
- }
-
- public void render(Graphics g) {
- //Tegn ben, arme, etc..
- g.drawLine(.....);
- }
- }
-
- public class Car implements GameObject {
-
- public void update() {
- if (engineOn) {
- fuel -= fuelConsumptionRate;
- }
- if (fuel <= 0) {
- fuel = 0;
- engineOn = false;
- }
- //etc..
- }
-
- public void render(Graphics g) {
- //Tegn hjul, karosseri, etc..
- }
- }
Forestil dig et spil. Interfacet beskriver ikke implementation, men adfærd. Ethvert game objekt skal håndtere sin egen game update og rendering ved brug af et Graphics objekt g. Du kunne have gjort det samme med en (abstrakt) klasse men det giver typisk store begrænsinger i sprog som Java og C# som har single-inheritance, siden så kan dine klasser ikke arve fra noget andet. Men det gør også sådan noget her muligt på en renere måde:
- public class GameEngine {
- //Instansvariabler etc..
- public void Main() {
- while (runGame) {
- for (GameObject go : getAllObjects()) {
- go.update();
- go.render();
- }
- }
- }
- }
Uden en fælles interface eller klasse, ville dette ikke være muligt uden at checke typen på 'go' hele tiden og så caste til den rigtige type, hvilket hurtigt bliver ukontrollerbart når man tilføjer fly, aliens, bygninger og andre klasser.