När ska jag använda abstrakta klasser och gränssnitt (Interface)? - Java

Permalänk

Nu tror jag att jag har greppat detta angående abstrakta klasser och gränsnitt.

Jag börjar först att göra en abstrakt klass för fordon, vid namn Vehicle.java. Där beskriver jag abstrakt hur ett fordon är. Alltså sammanfattande hur generellt ett fordon brukar se ut, beter sig, hastighet osv.

package com.company; public abstract class Vehicle implements IRobot { private String brand; private int age; private double length; private double speed; private int wheels; public Vehicle(String brand, int age, double length, double speed, int wheels) { this.brand = brand; this.age = age; this.length = length; this.speed = speed; this.wheels = wheels; } public void oil(){ } public void connect(){ } public void startUp(){ } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getLength() { return length; } public void setLength(double length) { this.length = length; } public double getSpeed() { return speed; } public void setSpeed(double speed) { this.speed = speed; } public int getWheels() { return wheels; } public void setWheels(int wheels) { this.wheels = wheels; } }

Jag gör likadant med en abstrakt klass som heter Person.java. Där beskriver jag abstrakt hur en person är.

package com.company; public abstract class Person implements IRobot { private String name; private int age; private double height; private double speed; public Person(String name, int age, double height, double speed) { this.name = name; this.age = age; this.height = height; this.speed = speed; } public void talk(){ } public void stay(){ } public void start(){ } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getHeigth() { return height; } public void setHeigth(double heigth) { this.height = heigth; } public double getSpeed() { return speed; } public void setSpeed(double speed) { this.speed = speed; } }

Nu tänker jag skapa en klass som heter Robot.

public class Robot { private String microprocessor; private boolean terminator; private boolean nucelarPower; public Robot(String microprocessor, boolean terminator, boolean nucelarPower) { this.microprocessor = microprocessor; this.terminator = terminator; this.nucelarPower = nucelarPower; } }

Klassen Robot ska ärva lite metoder och parametrar från både Person och Vehicle. Då använder jag ett gränssnitt.

public interface IRobot { public void oil(); public void connect(); public void startUp(); public void talk(); public void stay(); public void start(); public void setName(String name); public String getName(); public int getAge(); public void setAge(int age); }

Men när jag kör denna kod så får jag error

IRobot iRobot = new Robot("AT-mega", false, true); <<<<----- Denna fungerar inte! String name = iRobot.getName(); System.out.println("The robot name is: " + name); iRobot.setName("vICky"); name = iRobot.getName(); System.out.println("The robot name is: " + name);

Permalänk

Men klassen robot implementerat ju inte iRobot bara veichle och person gör ju de. Dvs de är bara dom 2 som kan skapas och hanteras som en iRobot.

Permalänk
Skrivet av fizzyflaskan:

Men klassen robot implementerat ju inte iRobot bara veichle och person gör ju de. Dvs de är bara dom 2 som kan skapas och hanteras som en iRobot.

Så hur ska jag göra för att kombinera vissa metoder och parametrar från Vehicle och Person i klassen Robot?

Permalänk
Medlem

Jag tror du fortfarande missförstått poängen. Ta bilden här nedan för exempel och börja med grunderna för arv och varför det används.

Figure är super-klassen här och har metoder och instansvariabler som är gemensamma för både cirkel och fyrkant. Dessa ärver då (extends Figure) dessa variabler och metoder från Figure, vilket är vad pilen betyder. Vad det betyder är i kort att du slipper skriva koden för exempelvis color två gånger, då den ändå används i båda subklasserna.

Anledningen att göra Figure till abstrakt är för att den egentligen aldrig används som objekt, den är bara till för att vara den gemensamma nämnare mellan Square och Circle för att slippa skriva koden flera gånger. Det är dessutom relativt enkelt att lägga till ytterligare former som kan samlas i samma lista. Om du då har alla former i samma lista så kan du lätt gå igenom listan och göra vad du behöver.

ArrayList<Figure> figures = new ArrayList<Figure>; //En lista med alla figurer figures.add(new Circle(point, radius)); //Lägg till de objekt du ska ha figures.add(new Square(point)); for (Figure f: figures){ if (f instanceof Circle){ //instanceof kan användas för att särskilja mellan olika objekttyper i listan sout("this is a circle"); } }

Om du däremot som i ditt fall inte tänkt använda olika typer av subklasser så kan det ju diskuteras hur långt man ska abstrahera koden över huvudtaget. Vehicle, Robot och Person är åt pipsvängen för långt ifrån varandra för att ens orka hitta en logisk arvskedja vid denna tidspunkt. Förhoppningsvis kommer det någon som orkar förklara interface

Permalänk
Medlem
Skrivet av heretic16:

Så hur ska jag göra för att kombinera vissa metoder och parametrar från Vehicle och Person i klassen Robot?

Du kan skapa en mellanliggande abstrakt datatyp (klass) som innehåller mer information. Exempel

abstract class A { public int foo = 1; } abstract class B extends A { public int bar = 2; } class C extends B { public C(foo, bar) { this.foo = foo; this.bar = bar; } }

För många arv gör din design väldigt stel och jobbig att arbeta med. Det blir liksom alltid hårklyverier: Kan alla människor verkligen prata? Hur är det med stumma människor? Bebisar? Tystnadslöfte? Stoppar vi in en ny klass i mitten av arvskedjan som heter Being och representerar något som inte nödvändigtvis kan prata så blir det en massa omstrukturering bland klasserna för att flytta metoder till den nya klassen osv.

Java har som sagt inte stöd för multipla arv — men en klass kan implementera flera "interfaces". Sedan Java 8 har interfaces fått stöd för default methods vilka tillåter arv av metoder, med den begränsningen att de metoderna inte kan påverka en instans tillstånd (state).

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Skrivet av heretic16:

Så hur ska jag göra för att kombinera vissa metoder och parametrar från Vehicle och Person i klassen Robot?

Kortfattat: Det kan du inte pga. att multipla arv inte är tillåtna i java.

Jag förstår tanken bakom din kod att interfacet på något vis skulle agera medlare mellan två olika klasser, som en sorts multipelt arv, men det fungerar inte riktigt så.

Ok, ett annat sätt man kan se det är så här. Ett interface är ett certifikat. När du implementerar ett interface i en klass så är interfacet ett certifikat på att klassen har de funktioner som interfacet specificerar. Interfacet i sig själv innehåller absolut ingen data, det är bara en lista över saker klassen lovar den kan göra, och i vilka format den vill ta emot samt returnera data.

Abstrakta klasser verkar du dock ha fått kläm på. De är helt enkelt som vanliga klasser med viktigaste undantaget att de inte går att skapa objekt på, så man använder dem i regel som superklass för underklasser som har väldigt mycket gemensam logik.

Sen kanske du undrar: "varför ens använda abstrakta klasser när jag kan använda vanliga klasser ? det är ju trots allt jag själv som väljer vilka klasser jag behöver skapa objekt på."
Detta är förvisso väldigt sant, men föreställ ett gigantiskt projekt med flera tiotusentals rader kod och 20+ utvecklare som jobbar tillsammans på det. Ibland kan det vara bra att ha en begränsning så att inte någon annan skapar objekt på en klass som inte är menad för det.
Det är lite pga. samma scenario som Interface kom in i bilden. När flera kodare jobbar på samma projekt så kan det vara bra att ha "certifikat" på vissa klasser så man vet att de kan utföra det där specifika arbetsmomentet man behöver, samt man vet vilka värdetyper som förväntas och/eller returneras.

Jag kan tyvärr varken förklara det bättre, eller demonstrera det bättre än vad jag redan försökt. Mitt tips är att om det känns för luddigt så lägg inte så mycket vikt vid Interface just nu. Fokusera på klasser och abstrakta klasser och relationen mellan de två. Man kan göra enormt mycket utan att ens använda sig av Interface, så det är ingen livsviktig komponent i programmering.
Återuppta konceptet sen när du har full koll på klasser och arv.