I am trying to wrap my head around object oriented programming.
My understanding is that we have objects so we can design our programs to mirror real-life objects.
Let's take a class hierarchy:
class Fruit {
void Eat() {
}
}
class Apple extends Fruit {
}
Obviously, you can use Fruit polymorphically if Eat()
is virtual. But does this make sense? Fruit cannot eat itself!
Should a fruit object rather be passed to a human object which has a Eat()
function?
I am trying to figure out the correct way to think about this. How closely, in general, should programming objects mirror real-life objects?
You're correct that probably eat() would be a method of a human or mammal or fruitFly. A fruit itself probably has no behaviour, and hence no methods.
I don't often consider the benefits of OO in realtion to the mapping from real things to Object. That's probably because we deal with less tangible concepts such as Invoices and Orders.
I see the primary win from OO to be in the structure it brings to my code. In the real world Invoices and Orders don't actually do anything, but in my code they do. So the programmtic Order may well be much closer to the combination of the data representing an order, and some human business process relevent to the order.
I always find examples using 'animals' or 'fruit' counter-intuitive. People are difficult objects to model, and it's unlikey that you'll encounter applications with the same requirements.
Using the concept of anthropomorphisation can really help assign reponsibilities. Basically, imagine that your object is a person (I typically sketch them with a face and limbs during design sessions).
Now you can ask these questions about your object:
"Object Thinking" by David West is a good book to read on the topic.
I don't think we should try to "mirror real-life objects". I think it's more of finding real life objects that closely resemble the behavior being modeled within the context of the system (domain). A Fruit class in a game where you slice fruit for points might have drastically different behaviors and attributes than the Fruit class in a game where a character runs around collecting fruits for points; or a simulation of people eating fruits. Assigning behaviors to classes named after real life objects makes it easier to assume the behavior of code modules and speculate on their interactions.
I think you should read the SOLID principles, it's going to help you a lot. http://www.lostechies.com/blogs/chad_myers/archive/2008/03/07/pablo-s-topic-of-the-month-march-solid-principles.aspx
You've got a design problem -- as you correctly point out, Eat() doesn't make obvious sense as a member of Fruit. On the other hand, an "edible" attribute would make more sense. As would an "onEaten" event, etc. What your fruit/apple classes expose (and what other objects make sense in your model) depends on a lot of other factors, including what you're trying to accomplish with those constructs in your application.
In general you want your classes to represent logical domain level entities. Sometimes those correspond to a physical entity in the real world, but in many cases they don't.
In my opinion OO problem decomposition is something programmers are generally pretty bad at. I don't know how many times I've seen the equivalent of a car derived from a steering wheel and shaken my head while the original developer couldn't wrap their head around why their design didn't make a lot of sense.
Assuming you were, say, writing a hungry people simulator, then I think it would make much more sense to, as you say, have a
Human::Eat(Fruit f)
function. Your Fruit might not have methods since Fruit doesn't do much on it's own, but it might have acalories
property, and so on.