Permalänk
Medlem

Fråga angående arv.

Hej, jag håller på att bygga en liten hierarki av djur, där djur är bas klassen och sedan har jag hund, fågel, fisk och under fisk, haj.
Tanken är att jag ska lägga klasser för köttätare, allätare och vegetarian. Man hur jag än vänder och vrider på det så tycker jag inte att dom passar in i arvsträdet riktigt.
Någon som har ett tips hur man kan lägga upp det?

Mvh

Permalänk
Medlem

Djur > Kategori > Typ, typ?

Djur, alla djur är djur, attribut som alla djur har.
Kategori, typ däggdjur
Typ, Hund, katt, häst.
Vidare kan du lägga till raser om det behövs.

Att ha en klass för vad de äter skulle nog inte fungera så bra, skulle bli redundans osv. Du har ju t.ex. hajar som inte äter kött. Skulle istället ha det som attribut för djur, ifall det nu skulle fungera för det du vill göra.

Permalänk
Medlem

Ja det är nog så jag får göra det, men I uppgiften jag fått står det att jag ska lägga in mellan klasser som te.x köttätare eller gräsätare. Men det kanske var en baktanke med det hela.

Permalänk
Medlem
Skrivet av CheeO:

Ja det är nog så jag får göra det, men I uppgiften jag fått står det att jag ska lägga in mellan klasser som te.x köttätare eller gräsätare. Men det kanske var en baktanke med det hela.

Kolla in hur det är klassificerat på ex Wikipedia.
http://en.wikipedia.org/wiki/Eurasian_lynx

Kingdom: Animalia
Phylum: Chordata
Class: Mammalia
Order: Carnivora
Family: Felidae
Genus: Lynx
Species: L. lynx

Permalänk
Medlem

Kanske inte det du söker, men det finns ett koncept som heter multipelt arv, som bl.a. c++ stödjer. Där en klass kan ärva från flera klasser. I andra språk löser man det genom interface (vilket en klass kan implementera flera av).

Skickades från m.sweclockers.com

Visa signatur

..:: RiJo ::..
Computer: Lenovo X300
Platform: Gentoo

Permalänk
Medlem

Nu är jag inte den bästa på detta, och du kommer säkert få mer korrekt av dem som vet mer. Men jag skulle hålla på med arv och polymorphism, där du skriver över den generella metoden för det specifika djuret.

ex.

Något som alla djur har gemensamt är att dem äter. Du behöver inte skapa en "äta" metod för varje djur, det räcker med att root classen erbjuder den funktionen. Däremot kanske en fisk äter på ett specifikt sätt, en hund på ett annat och en fågel på ett tredje. Då kan du använda dig av polymorphism, där du "skriver över" den ärvda metoden med din egna specifika för den klassen.

Ex:

Jag skriver i Java då det jag är bekväm med

public class Animal { public void eat (int food) { int a = food; } }

Denna är ganska generell för varje djur, därmot kanske du har en hund klass som ärver animal och där kan du skriva om själva eat till något annat just för specifikt hund. Fördelen med detta är att du kan skapa en generell äta metod, och äter någon på ett annat sätt så behöver du bara göra det för specifikt den klassen.

public class Dog extends Animal { public void eat (int food) { int b = food; } public void eat (int food, boolean eat) { int a = food; isEaten = eat; } }

Det går att läsa mer om polymorphism på oracles dokumentation: http://docs.oracle.com/javase/tutorial/java/IandI/polymorphis...
Java är ett annat språk, men jag vågar påstå att fundamentalet är likadant.

Permalänk
Medlem
Skrivet av Razki:

Nu är jag inte den bästa på detta, och du kommer säkert få mer korrekt av dem som vet mer. Men jag skulle hålla på med arv och polymorphism, där du skriver över den generella metoden för det specifika djuret.

ex.

Något som alla djur har gemensamt är att dem äter. Du behöver inte skapa en "äta" metod för varje djur, det räcker med att root classen erbjuder den funktionen. Däremot kanske en fisk äter på ett specifikt sätt, en hund på ett annat och en fågel på ett tredje. Då kan du använda dig av polymorphism, där du "skriver över" den ärvda metoden med din egna specifika för den klassen.

Ex:

Jag skriver i Java då det jag är bekväm med

public class Animal { public void eat (int food) { food = 2; } }

Denna är ganska generell för varje djur, därmot kanske du har en hund klass som ärver animal och där kan du skriva om själva eat till något annat just för specifikt hund. Fördelen med detta är att du kan skapa en generell äta metod, och äter någon på ett annat sätt så behöver du bara göra det för specifikt den klassen.

public class Dog extends Animal { public void eat (int food, boolean eat) { food = 2; eat = true; } }

Det går att läsa mer om polymorphism på oracles dokumentation: http://docs.oracle.com/javase/tutorial/java/IandI/polymorphis...
Java är ett annat språk, men jag vågar påstå att fundamentalet är likadant.

Det är förvirrande att dina metoder tar parametrar, parameterar som direkt sätts om till nya värden och aldrig används.
En annan sak som verkar lite konstig är att Dog i ditt exempel kommer ha två eat-metoder.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Skrivet av Teknocide:

Det är förvirrande att dina metoder tar parametrar, parameterar som direkt sätts om till nya värden och aldrig används.

Ursäkta Ville bara illustrera att samma metod kunde ändras och/eller skrivas om under samma klass i ett arv-sammanhang. Tänkte inte lägga allt för mycket tid att skriva en kommentar, mer att pusha mot en riktning

edit. dock sant, när jag kollar på dem specifikt. Skrev dem i en befintlig annan klass jag hade, så jag kollade inte på om koden var korrekt

Permalänk
Medlem
Skrivet av CheeO:

Hej, jag håller på att bygga en liten hierarki av djur, där djur är bas klassen och sedan har jag hund, fågel, fisk och under fisk, haj.
Tanken är att jag ska lägga klasser för köttätare, allätare och vegetarian. Man hur jag än vänder och vrider på det så tycker jag inte att dom passar in i arvsträdet riktigt.
Någon som har ett tips hur man kan lägga upp det?

Mvh

Hej!
Du har en mycket bra fråga. Det finns lite olika lösningar beroende på hur det är tänkt att fungera.

Om du bara vill veta om ett 'Djur' är köttätare, allätare eller vegetarian, så skulle detta kunna returneras av en metod i basklassen 'Djur' som varje djur implementerar. Lämpligtvis är metoden då abstract i 'Djur'.

Om det är någon logik som ska köras beroende på om ett 'Djur' är köttätare, allätare eller vegetarian (vilket det oftast är om vi inte bara ska lista data) måste vi tackla problemet lite annorlunda.

Säg det finns en metod som heter t.ex. bool Eat(IFood food) som ska tala om för oss om djuret kan äta maten och också äta maten om möjligt. Om vi lägger metoden i basklassen 'Djur' och logiken är unik för köttätare, allätare och vegetarianer kommer det snabbt uppstå ett problem i form av copy-past programmering om vi försöker implementera den för varje enskilt djur. D.v.s. du kommer upptäcka att du har samma kod på flera ställen för djur som äter samma saker. Det är alltså inte en tillräckligt bra lösning.

Multipelt arv har nämnts. Problemet med multipelt arv i detta fallet är att det öppnar upp för problem som alltid genom att göra programmet onödigt komplext när det inte behövs. Multipelt arv är starkt när det används rätt men detta är inte ett sådant fall. Multipelt arv är också mindre flexibelt än alternativa lösningar.

Så hur ska man göra då? Jag skulle i detta fall satsa på något som kallas "Component Based Design". Det innebär att man t.ex. gör ett interface "IEatComponent" som har metoden "Eat" som nändes ovan. Sedan ärver vi detta interfacet för varje typ, d.v.s. köttätare, allätare och vegetarian. I basklassen 'Djur' lägger vi till en referens till en "IEatComponent". Sedan lägger vi också till "Eat" metoden i 'Djur'. I "Eat" metoden i 'Djur' anropar vi sedan "Eat" metoden från "IEatComponent" referensen. Detta skulle kunna se ut ungefär så här:

interface IEatComponent { bool Eat(IFood food); } -------------------------------------------------- class Djur { public bool Eat(IFood food) { return eatComp.Eat(food); } private IEatComponent eatComp; }

Denna lösningen eliminerar "copy-past" programmeringen, inför inte onödig komplexitet och är mer flexibelt än multipelt arv. Ett djur kan ju nu t.ex. enkelt byta mellan att äta olika saker bara genom att ändra "IEatComponent" referensen. Kanske äter ett djur andra saker som liten än vuxen, jag vet inte så jag föredrar att ha den flexibiliteten kvar vilket just är charmen med denna lösningen. Enkelt att ändra och att underhålla.

Bonus: För ett antal år sedan stötte man på denna problematiken i spelvärden då spel motorer blev allt mer avancerade och arvsträdet blev allt djupare. Det resulterade i att felaktiga arv gjordes och motorn blev allt mer buggig och oflexibel. Lösningen till detta var "Component Based Design" vilket idag i princip alla stora spelmotorer använder t.ex. "Unreal Engine 4".

Permalänk
Medlem

Tack så mycket för alla svar, och intressant läsning RaBox.