Explaining OOP Without Mentioning Classes, Part 2: The Basics
Posted by Ben Jackson Sat, 03 Dec 2005 13:48:00 GMT
My last post on this subject was the most popular article I've written to date. It seems like I struck a chord somewhere with the masses of amateur programmers who are sick of wading through code samples to to get the information they want. So, today I bring you the second of what I've now decided will be three installments.
What is an Object?
An Object is a role. Imagine your program is an assembly line. Each Object has a certain set of knowledge about the state of the program, and can be called upon to perform a set of related tasks. These can be requests for information, or commands for the object to do something. For example, a program might ask a Circle for its radius, or its circumference, or to draw itself. What the object does behind the scenes is none of the program's business; in fact, the less it knows, the better.
So how do I make one of these?
You write a definition for the compiler. Most object-oriented programming languages (C++, Ruby, and Actionscript, for example) call this a class (I can get away with mentioning that once, can't I?).
Basically your definition is a list of the information each object has available to it, as well as the services it can be called upon to perform. For our Circle, that would mean a variable radius, and two functions, getCircumference() and draw(). These variables and functions are public, which means that anyone can access them, and they define the interface of your object. The interface is your Object's only means of providing information or receiving requests for action.
Private functions can only be called by the object itself (this is simplifying, but go with me for now), and can be thought of as the stuff that it does when it thinks no one is looking (functions like pickNose() and singAlongToPrinceAtHighVolume() come to mind). If the public functions are the factory managers, then the private functions are the oil-stained, underpaid wage slaves. They usually get written when you realize that you need to do the same thing in two different places in the code (for example, if you have a bunch of functions that need to do some complex calculation). Rather than copying and pasting code, it's smarter to put it into a single place. After all, if you need to do the same thing twice, chances are that you'll need to do it again pretty soon.
Public and private variables follow the same pattern, with public variables being visible to all and private ones being shielded from meddling hands.
It's good to keep your interfaces small and well-defined. Describe your object as noun with an (optional) verb:
"Manages layout." LayoutManager. "Connects to database." DatabaseConnector. "Creates Widgets." WidgetFactory.
Why do this? Keeping your interfaces well-defined lets you change things up behind the scenes (for example, to improve performance or deal with new requirements) without breaking anything that depends on your code. And the less an Object does, the less that can go wrong. And when problems do arise, you know exactly who's to blame. For example, if your program suddenly starts cursing at you in Greek, the Logger is probably having an identity crisis.
Inheritance
Sometimes we have a few types of objects that share a bunch of common traits. A Circle, Square, and Triangle are all Shapes, right? If I'm writing a drawing function, I don't want my code to have to change depending on the kind of shape (especially given the client's reputation for last-minute design changes). So I define my Shape with a method draw(), and each type of shape will perform this action differently when it's called. To tell the compiler about this, I say that Circle extends Shape. Any function that I call on Circle will go up the ladder until it finds an ancestor with a definition for it.
Caveat: only use this if there is a clear set of ties between a bunch of objects. For example, an Audi 500 and a Dodge Caravan could easily be descendents of Car. It's not always that cut-and-dried, though. For example, are Customer and Employee different types of Person? What happens when the CEO buys a new convertible?
Overuse of inheritance is one of the most common and annoying mistakes that programmers make when switching to OOP. Composition or Extension can go a long way and provide less headaches long term.
Coming Soon
For the next round, I'm gonna cover advanced topics in OOP, with a special section on how not to shoot yourself in the foot when designing object-oriented systems.

Thanks for another good article. I'll be looking for your next post.
Great stuff, thanks, this has cleared up a lot for me!