2009-11-29 27 views

Respuesta

13

Bueno, aquí hay uno bueno que se me ocurrió - la utilización primordial programación orientada a objetos, subclase y superclase:

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{ 

    } 

} 

puedo crear subclases herbívoro, carnívoro y omnívoro del animal superclase y reemplazar el método eat con el tipo de comida que realmente puede comer.

Así:

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 

Pues bien, el problema final es que, cuando se especifica que es un deerHerbivore, no se puede hacer un Meat para tiger para comer. Sin embargo, al final del día, esto debería ser suficiente para resolver el problema de la entrevista sin dejar dormido al entrevistador.

+2

Downvoted, porque ha clasificado a un venado como animal en un lugar y como alimento en otro. La misma instancia de ciervo puede ser ambas cosas; el tigre puede atacar al ciervo mientras come sus arbustos pacientemente. –

+0

Sé que ese es un problema que he estado tratando de resolver aquí. Tendré que crear una nueva clase y hacer que Deer pueda ir de 2 maneras. Recuerde: solo downvote si la publicación es completamente inútil y no vale la pena que los demás la vean y probablemente debería tener una mejor respuesta. – mauris

+0

Modelo incorrecto: Si le dan Hierba al Tigre, ella regresará al método 'come()' predeterminado para todos los animales. Debe agregar una función que arroje una excepción (o arroje al cuidador del zoológico) si intenta alimentar a Grass to the Tiger. –

0

No hay una mejor solución. Es posible que desee hacer de esta una wiki de la comunidad, ya que generalmente es la práctica aceptada para preguntas subjetivas.

Pienso en lo que realmente sería la mejor clase para las jerarquías, y trato de descubrir qué significa "lo mejor" en ese contexto.

Todo lo que hay Cosas, que podría tener un atributo de Nombre. Pero todo lo que hay en algún nivel es comida; si puede comer algo, algo puede comerlo. Podría hacer que Food sea la clase padre, y darle un método que devuelva un valor booleano para verificar si el objeto parámetro puede comer el objeto actual.

Así,

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

Eso parece la jerarquía de clases más simple que se ajusta a todo lo que pueda necesitar en un primer paso?

Dicho esto, la parte más importante en la mayoría de las preguntas de la entrevista es la sensación que se tiene para el entrevistado, no tanto la respuesta exacta que dan.

8

Hay un cartel maravilloso para la Liskov Substitution Principle que dice: "Si se ve como un pato, grazna como un pato, pero necesita baterías, es probable que tenga el abstracción mal." Y esa es la respuesta rápida: algunos de los objetos pueden ser tanto animales como alimentos, por lo tanto, a menos que esté dispuesto a seguir la ruta de la herencia múltiple, entonces el esquema de clasificación es incorrecto.

Una vez que ha superado ese obstáculo, el resto es abierto, y puede incorporar otros principios de diseño. Por ejemplo, podría agregar una interfaz IEdible que permita consumir objetos. Puede ir orientado a los aspectos y agregar decoradores para carnívoros y herbívoros, y eso permitiría el consumo de solo la clase correcta de objetos.

El punto es ser capaz de pensar sobre sus pies, ver y explicar varios aspectos de un problema, y ​​comunicarse bien. Y tal vez no para atascarse en una limitación de "una respuesta correcta".

1

He aquí algunos pensamientos sobre esta cuestión entrevista:

Estoy de acuerdo con Cylon Gato: (., Incluso si se trata de las interfaces de Java del mismo tipo) Este tipo de abstracción no funciona bien sin la herencia múltiple

lo haría crear dos formas de herencia:

Animal:

  • carnívoro
  • Su bivore

Alimentación:

  • carne
  • vegetal

El método de "comer" de los dos tipos de animales (estoy haciendo caso omiso de omnívoros, insectívoros, y muchos otros tipos) estaría especializado en los diferentes tipos de alimentos. Si estamos usando un lenguaje como Java, entonces Food sería una interfaz.

6

Le diría que se rasque eso. Es una abstracción horrible. Sin mencionar que no tenemos ningún contexto. Las abstracciones no surgen de la nada, o de una "idea" de lo que es "correcto". Muéstreme qué problema está tratando de resolver primero, para que podamos evaluar esta abstracción.

Si no se proporciona ningún contexto, entonces asumiré/compensaré el mío: querrás algunos tipos de objetos para poder comer otros tipos de objetos. Nada más y nada menos.

Hacer una interfaz de Eatable (o se le puede llamar Food, si lo desea), y puesto que no tenemos el contexto de lo que nunca, voy a asumir que es un programa de consola juguete, que sólo impresiones:

<X> ate <Y> 

, así que todo lo que necesitamos para esta interfaz es un método getFoodName().

Para la comprobación de errores, puede crear un grupo de isXFoodType métodos, por ejemplo, isGrassFoodType(), isMeatFoodType(), etc. implementación de Eat(Eatable e) El Cow 's comprobaría para isGrassFoodType(), y cuando falla, grabados:

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

-1. El polimorfismo es así que no necesitamos escribir código que examine tipos en tiempo de ejecución, como los métodos de isXFoodType. – outis

+0

@outis: el purismo así es malo para tu salud. – hasen

4

Alan Kay, quien acuñó el término "programación orientada a objetos", ha dicho "OOP para mí solo significa mensajería, retención y protección local y ocultamiento del proceso de estado, y enlace extremo de todas las cosas".

Tratando de solucionar este "problema" en el modelo de datos me suena a lo contrario de la vinculación tardía: ¿por qué necesita el compilador para hacer cumplir esto? No me preocuparía cambiar el modelo en absoluto. Si le pasan algo que no puede comer, lanza una excepción, ¡como en la vida real, casi!

1

Cualquier animal es alimento, cualquier vegetal es alimento. Y, de hecho, un tigre puede ser comido por una vaca. (El prurigo lumbar de la enfermedad priónica se transmite al alimentar el tejido neural de las ovejas infectadas con ovejas no infectadas).

Puede tener una jerarquía de especies, ala Linnaeus, tanto animal como vegetal.Cada especie es un Singleton, y tiene un List<Species> que registra su dieta típica. Elimine la jerarquía de Alimentos por completo, solo confunde las cosas.

Y, si su único problema es registrar la dieta para cada especie, entonces las múltiples clases de Especies son innecesarias. Solo tiene una única clase de Especie con el nombre de la especie como una variable de instancia y el List<Species> como otro.

0

Si esperas que el sistema sea muy grande, te sugiero que subclases plantas/carne y herbívoro/carnívoro/omnívoro.

Asegúrese de que el sistema tenga una interfaz estándar para todas las plantas/animales llamada getFoodName() y getFoodType(), puede aplicar esto creando una clase principal para plantas/animales llamada species.

El problema que vería con la planta de subclasificación/carne y carnívoro/herbívoro es que una suricata es carnívora pero es probable que no pueda comer un rinoceronte (puede haber un mejor ejemplo), por lo que se necesitan algunas restricciones " Como carne, comes plantas ".

Si no fuera a ser increíblemente grande y quisieras ser neurótico al respecto, podrías almacenar enumeraciones estáticas de alimentos permitidos para cada subclase de animal. Así que el tigre podría almacenar ciervos, antílopes, etc.

3

La comida debería ser una interfaz, por lo tanto, las plantas y los animales también podrían ser alimentos.

resumen La clase de animal debe tener el método de comer que tome la comida como parámetro.

subclases de Animal: carnívoro, herbívoro y omnívoro deben tener su propia versión de comer.

Por ejemplo, para Carnivore:

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

Los problemas resueltos.

Pero para un mejor diseño, Carnivore, Herbivore y Omnivore también deberían ser interfaces, ya que no son la forma correcta de etiquetar a los animales.

2

Esto es fácil con los genéricos en 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 
{ 
} 

Uso:

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 
Cuestiones relacionadas