2009-11-29 17 views

Antwort

13

Nun, hier ist ein guter, die ich kam mit - unter Verwendung von OOP überwiegendem, Unterklasse und Oberklasse:

namespace Animals{ 

    // base class Animal 
    class Animal{ 

    public void eat(Food f){ 

    } 

    } 


    class Carnivore extends Animal{ 

     public void eat(Meat f){ 

     } 

    } 

    class Herbivore extends Animal{ 

     public void eat(Plant f){ 

     } 

    } 

    class Omnivore extends Animal{ 

     public void eat(Food f){ 

     } 
    } 

} 

namespace Food{ 

    // base class Food 
    class Food{ 

    } 

    class Meat extends Food{ 

    } 

    class Plant extends Food{ 

    } 

} 

I-Subklassen Pflanzenfresser, Fleischfresser und Allesfresser aus dem übergeordneten Klasse Tiere erstellen und überschreibe die eat Methode mit der Art von Essen, das es tatsächlich essen kann.

So:

Plant grass = new Plant(); 
Herbivore deer = new Herbivore(); 
deer.eat(grass); // ok 

Plant grass2 = new Plant(); 
Carnivore tiger = new Carnivore(); 
tiger.eat(grass2); // not ok. 

Meat deer2 = new Meat(); 
tiger.eat(deer2); // ok 

Nun, das ist das letzte Problem, dass, wenn Sie angeben, dass deer ist ein Herbivore, können Sie es nicht ein Meat für tiger essen machen. Am Ende des Tages sollte dies jedoch ausreichen, um das Interviewproblem zu lösen, ohne den Interviewer einzuschläfern.

+2

Downvoted, weil Sie ein Reh als Tier an einer Stelle und als Nahrung in einer anderen eingestuft haben. Das gleiche Beispiel von Hirsch kann beides sein; Der Tiger kann die Rehe angreifen, während er Ihre Sträucher saftig isst. –

+0

Ich weiß, das ist ein Problem, das ich hier zu lösen versucht habe. Ich muss eine neue Klasse schaffen und Deer dazu bringen, 2 Wege gehen zu können. Denken Sie daran: Wenn Sie den Beitrag nur nutzlos nutzen und nicht wert sind, von anderen gesehen zu werden, sollten Sie ihn nur ablehnen. Sie sollten wahrscheinlich eine bessere Antwort erhalten. – mauris

+0

Schlechtes Modell: Wenn dem Tiger Grass gegeben wird, kehrt er für alle Tiere zur Standardmethode 'essen()' zurück. Sie müssen eine Funktion hinzufügen, die eine Ausnahme auslöst (oder den Tierpfleger wirft), wenn Sie versuchen, Grass dem Tiger zu füttern. –

0

Es gibt keine beste Lösung. Vielleicht möchten Sie dies zu einem Community-Wiki machen, da dies im Allgemeinen die akzeptierte Praxis für subjektive Fragen ist.

Ich würde darüber nachdenken, was würde eigentlich die beste Elternklasse für die Hierarchien machen, und versuchen herauszufinden, was "am besten" in diesem Zusammenhang bedeutet.

Alles da sind Dinge, die ein Name-Attribut haben könnten. Aber alles dort auf einer Ebene ist Essen; wenn es etwas essen kann, kann etwas es essen. Ich könnte Food zur Elternklasse machen und eine Methode geben, die einen Booleschen Wert zurückgibt, um zu prüfen, ob das Parameterobjekt das aktuelle Objekt essen kann.

So

class Food { 
    boolean canBeEatenBy(Food hungryObject) 
    String name 
} 

, dass die einfachste Klassenhierarchie scheint, dass alles paßt ich auf einem ersten Durchlauf benötigen könnte?

Das Gesagte, der wichtige Teil in den meisten Interviewfragen ist das Gefühl, das Sie für den Interviewten bekommen, nicht so sehr die genaue Antwort, die sie geben.

8

Es gibt ein wunderbares Plakat für das Liskov Substitution Principle, das sagt, "Wenn es wie eine Ente aussieht, quakt wie eine Ente, aber benötigt Batterien, Sie haben vermutlich die falsche Abstraktion." Und das ist die schnelle Antwort - einige der Objekte können sowohl Tiere als auch Nahrung sein. Wenn Sie also nicht den Weg der Mehrfachvererbung gehen wollen, dann ist das Klassifikationsschema alles falsch.

Sobald Sie diese Hürde genommen haben, ist der Rest offen, und Sie können andere Designprinzipien einbringen. Sie könnten beispielsweise eine IEdible-Schnittstelle hinzufügen, mit der Objekte konsumiert werden können. Du könntest aspektorientiert gehen und Dekorateure für Fleischfresser und Pflanzenfresser hinzufügen, und das würde erlauben, nur die richtige Klasse von Objekten zu konsumieren.

Der Punkt ist, in der Lage zu sein, auf Ihren Füßen zu denken, verschiedene Aspekte eines Problems zu sehen und zu erklären, und gut zu kommunizieren. Und vielleicht nicht auf eine "eine richtige Antwort" Begrenzung stecken bleiben.

1

Hier einige Gedanken zu diesem Interview Frage:

ich mit Zylon Cat zustimmen: (. Auch wenn es Java-ähnliche Schnittstellen ist) Diese Art von Abstraktion ohne Mehrfachvererbung funktioniert nicht gut

würde ich erstellen zwei Formen der Vererbung:

Tier:

  • Carnivore
  • Her bivore

Nahrung:

  • Fleisch
  • Gemüse

Die "essen" Methode der zwei Arten von Tieren (I Omnivoren bin ignorieren, Insektenfresser, und viele andere Arten) wäre für die verschiedenen Arten von Lebensmitteln spezialisiert. Wenn wir eine Sprache wie Java verwenden, dann wäre Essen eine Schnittstelle.

6

Ich würde ihm sagen, das zu kratzen. Es ist eine schreckliche Abstraktion. Ganz zu schweigen davon, dass wir keinen Kontext bekommen. Abstraktionen entstehen nicht aus der Luft oder aus einer "Idee" dessen, was "richtig" ist. Zeigen Sie mir, welches Problem Sie zuerst lösen wollen, damit wir diese Abstraktion bewerten können.

Wenn kein Kontext zur Verfügung gestellt wird, dann nehme ich einfach/make-up mein eigenes: Sie wollen, dass einige Arten von Objekten andere Arten von Objekten essen können. Nicht mehr, nicht weniger.

Machen Sie eine Eatable-Schnittstelle (oder Sie können es Food nennen, wenn Sie möchten), und da wir keinen Zusammenhang haben, was so überhaupt, ich nehme an, es ist ein Spielzeug-Konsolenprogramm, das gerade druckt:

<X> ate <Y> 

so alles, was wir für diese Schnittstelle benötigen, ist eine getFoodName() Methode.

Für die Fehlerprüfung, können Sie eine Reihe von isXFoodType Methoden erstellen, zum Beispiel, isGrassFoodType(), isMeatFoodType() usw. Die Cow ‚s Implementierung von Eat(Eatable e) für isGrassFoodType() überprüfen würde, und wenn nicht, druckt:

"Cow can't eat " + e.getFoodName() 
+2

-1. Polymorphie ist so, dass wir keinen Code schreiben müssen, der Typen zur Laufzeit untersucht, wie die isXFoodType-Methoden. – outis

+0

@outis: Purismus wie das ist schlecht für Ihre Gesundheit. – hasen

4

Alan Kay, der den Begriff "objektorientierte Programmierung" geprägt hat, hat gesagt: "OOP bedeutet für mich nur Messaging, lokale Speicherung und Schutz und Verstecken von State-Prozessen und extreme späte Bindung aller Dinge".

Der Versuch, dieses "Problem" im Datenmodell zu beheben, klingt für mich wie das Gegenteil der späten Bindung: Warum brauchen Sie den Compiler, um dies durchzusetzen? Ich würde mir keine Sorgen darüber machen, das Modell überhaupt zu verändern. Wenn du etwas passiert hast, das du nicht essen kannst, wirfst du eine Ausnahme - genau wie im richtigen Leben, so ziemlich!

1

Jedes Tier ist Nahrung, jedes Gemüse ist Nahrung. Und tatsächlich kann ein Tiger von einer Kuh gegessen werden. (Die Prionenerkrankung Scrapie wird durch Fütterung infizierten Schaf-Nervengewebe auf nicht infizierte Schafe verteilt.)

Sie könnten eine Hierarchie von Arten haben, ala Linnaeus, sowohl tierische als auch pflanzliche.Jede Art ist ein Singleton, und es hat eine List<Species>, die seine typische Ernährung aufzeichnet. Streiche die Food-Hierarchie komplett, es verwirrt nur die Dinge.

Und wenn Ihr einziges Problem ist Aufnahme Diät für jede Spezies, dann sind die verschiedenen Arten Klassen unnötig. Habe einfach eine einzelne Spezies-Klasse mit dem Spezies-Namen als eine Instanzvariable und die List<Species> als eine andere.

0

Wenn Sie erwarten, dass das System sehr groß wird, würde ich vorschlagen, Pflanzen/Fleisch und Pflanzenfresser/Fleischfresser/Allesfresser zu untergliedern.

Stellen Sie sicher, dass das System über eine Standardschnittstelle für alle Pflanzen/Tiere namens getFoodName() und getFoodType() verfügt. Sie können dies durch Erstellen einer Elternklasse für Pflanzen/Tiere, genannt Spezies, erzwingen. Das Problem, das ich mit der Unterklasse Pflanze/Fleisch und Fleischfresser/Herbivore sehen würde, ist, dass ein Erdmännchen Fleischfresser ist, aber es kann wahrscheinlich kein Nashorn essen (es gibt vielleicht ein besseres Beispiel), also sind einige Einschränkungen erforderlich. Ich esse Fleisch, esse Pflanzen ".

Wenn es nicht unglaublich groß werden würde und Sie neurotisch darüber sein wollten, könnten Sie statische Enums von zulässigen Lebensmitteln für jede Unterklasse von Tieren speichern. So könnte Tiger Hirsche, Antilopen usw. speichern.

3

Nahrung sollte eine Schnittstelle sein, daher könnten Pflanze und Tier auch Nahrung sein.

Abstract Tierklasse sollte essen Methode haben, die Nahrung als Parameter nehmen.

Unterklassen von Animal: Carnivore, Herbivore und Omnivore sollten ihre eigene Version von essen haben.

Zum Beispiel für Carnivore:

private void eat(Food food) 
{ 
     if(food instanceof Animal) 
     { 
      happilyEat(); 
     } 
     else 
     { 
      sniff&TurnAway(); 
     } 
} 

Die gelösten Probleme.

Aber für ein besseres Design sollten Fleischfresser, Herbivore und Omnivore Schnittstellen auch sein, da sie nicht die richtige Art der Kennzeichnung der Tiere sind.

2

Dies ist leicht mit Generics in C# btw:

public class Food 
{ 
} 

public abstract class Animal<T> : Meat where T:Food 
{ 
    public abstract void Eat(T food); 
} 

public class Herbivore : Animal<Plant> 
{ 
    public override void Eat(Plant food) 
    { 
     Console.WriteLine("Herbivore eats plants."); 
    } 
} 

public class Omnivore : Animal<Food> 
{ 
    public override void Eat(Food food) 
    { 
     Console.WriteLine("Omnivore eats food."); 
    } 
} 

public class Carnivore : Animal<Meat> 
{ 
    public override void Eat(Meat food) 
    { 
     Console.WriteLine("Carnivore eats meat."); 
    } 
} 

public class Plant : Food 
{ 
} 

public class Meat : Food 
{ 
} 

public class Cow : Herbivore 
{ 
} 

public class Tiger : Carnivore 
{ 
} 

public class Human : Omnivore 
{ 
} 

Verbrauch:

var human = new Human(); 
    var tiger = new Tiger(); 
    var cow = new Cow(); 
    var plant = new Plant(); 

    human.Eat(cow); 
    tiger.Eat(human); 

    cow.Eat(tiger); // this doesn't compile 
    tiger.Eat(plant); // neither does this