To set some context this question is designed to gauge the abstract and critical thinking of a generally inexperienced developer. I don't usually use this for very experienced developers, but may if I think I'm getting shallow or suspicious answers.
Here's what I start with:
I'm friendly but not at all helpful while I do this.
- I draw it out by hand on a whiteboard or on paper
- I verbalize the relationships
- I offer to explain the notation and meaning of "is-a"
- I ask them to think out-loud
- I hand them the writing instrument
- What's good? What's bad? What would you change?
- A "Deer" is an animal also.
- A "Cow" could be "Food" for a "Tiger".
Again, I ask them for their impressions.
If they don't get to it themselves I make sure to ask the following questions:
- What happens if a "Deer" is passed to the eat method of a "Cow"?
- How would you change the model to handle or avoid that problem?
18 comments:
Grass is not for tiger too...
We should delete tiger and move deer to animals.
Or delete grass and move cow to food...
Looks like wrong solution )
Thanks for this one. Much better than anything with foo and bar or how to implement a toString(); method.
I will use this in the future and it will be fun to see how far some might be able to take it (carnivore, herbivore, meat, vegetable, fruit, grain, etc...).
one thing i can think of very quick move deer under animal as well and implement Food for all that is eatable, except Tiger which is on top of the food chain. but must confess i am also newbie :)
i tried to write few lines of code as a solution
http://narup.blogspot.com/2008/08/answer-to-interview-problem.html
Turn Food into an interface so Animals can be Food also and use Generics to limit the food options in Animal subclasses. Did I get the job? :D
shouldn't we know about the context of the application this model is being designed for?
Or you are telling the interviewed your company creates model without a domain problem understanding?
because maybe this is the new nintendo game, "Tigers & Cows, Let's eat! (Deers and grass)"
Inheritence is a broken model for composing encapsulated object behavior.
Single inheritence even moreso.
What you should have is a mixin facility for "inheriting" individual methods or sets of methods.
And interfaces the define how an object may be cast, or to indicate a class can be used in such a manner.
Inheritence clumsily gives all the methods (and properties) to a descendent type. Well, public/private/protected/friend can provide additional limited granularity to the process, but you get the point.
OOP has been hamstrung by the crude, limiting effects of rigid hierarchical organization, with features like interfaces and mixins arising to try to address these limitations. The solution to provide a richer and more flexible range of tools to compose objects and at the same time prevent repeated/one-off code.
One more idea.
How about directed-graph-model?
tiger->cow
tiger->deer
cow->grass
deer->grass
Arrow means that left argument cat eat right one.
All is logical here I think )
strategy pattern or something ?
Given the first problem, assuming we don't have multiple inheritance I would say one of the hierarchy has to turn into an interface. Which one depending of the domain of the application.
Given the second issue I would say Animal would need a validation canEat(Food food) method that would check if the animal can eat the given food.
Implementation of this method would vary depending of the language used.
Thinking about it, there is another more simple solution :
Animal and vegetal inherit of food, deer inherit of animal and grass of vegetal.
Fits more real life I think.
canEat method stay, of course.
Add Beef and Venison inherit from food. Cow and Deer are animals. The Animal class should have a toMeat() method.
Wow, lots of fun comments. Thanks for the replies everyone.
I'd like to make two points:
1) Kudos to davidcr for providing the extra credit: purpose. Without knowing the purpose of a model there is really no good way to judge it. After a little head, scratching if a candidate asks that question then I can smell experience :)
2) I see many comments go right into classes and interfaces. Those are artifacts of a programming language, not necessarily modeling constructs. Very common artifacts... but still not key to this problem.
Here the definition of "is-a" is more like set theory or just intuitive categorization.
Cheers! John
well it's seems funny to ask for more information with the interviewer on this question because
you asked
1. What happens if a "Deer" is passed to the eat method of a "Cow"?
2. How would you change the model to handle or avoid that problem?
the problem is pretty much clear for this context
Interesting comments.
I'll stay with my Food on top.
Everything is food.
Who eat what is a behaviour, so it has to be designed as an operation.
After all, even if you can limit what some kind of animal eat to a list of food type, there are still rules like you don't eat your own species that is true for most of the animals as normal behaviour.
The first question I would ask is: What is the point of creating classes in the first place? If you are trying to model objects in the world, you could instead create a single object and have a single function tryToEat(eater : Object, food : Object) : Result, which would then check to see what the outcome of trying to eat something.
I presume that you want to model something as multiple objects because you want to *statically* check to see if you are doing something illegal. If so, then it really depends on the expressiveness of the language type system. Some languages can describe complicated relations between types, such as O'Caml and Scala - whereas some have a harder time.
One man's tiger is another man's meat.
How about below implementation:
---------------------------------------------------------------------
class Animal:
def eat(self):
raise NotImplementedError('Animal class not implemented')
class Food:
def chew(self):
raise NotImplementedError('Food class not implemented')
class Carnivore(Animal):
def eat(self, food):
if isinstance(food, Animal):
print 'Eating %s' % Animal
food.chew()
else:
print 'Cant eat'
class Herbivore(Animal, Food):
def eat(self, food):
if not isinstance(food, Animal):
print 'Eating %s' % Food
food.chew()
else:
print 'Cant eat'
def chew(self):
print 'Being eaten as Animal'
class Grass(Food):
def chew(self):
print 'Being eaten as Grass'
cow = Herbivore()
tiger = Carnivore()
deer = Herbivore()
grass = Grass()
tiger.eat(cow)
deer.eat(cow)
deer.eat(grass)
Post a Comment