If someone told you they'd inherited a million dollars, you could immediately surmise a few facts. It would be fairly logical to assume that they were preceded in life by someone with a million dollars, that this someone was a member of their family, and that this someone had recently died. Two of those observations are critical in OO's view of inheritance... and fortunately it's the first two. Nobody needs to die because of my blog, thank you very much.
In object-oriented software development, inheritance plays a very important, although often overused role. It works like this:
See how easy that was?
Inheritance deals with parents and children in the structure of an OO application's model. I can create a parent class, like "publication". A publication has a publisher, a release date, a revision number, and probably a total number of pages (if we're discussing print publications, which we are). NICE. But... I have a magazine, and a book. I need to track author and chapter names for the book. I also need to track article lists, advertisements, and writers for the magazine. While both "subclasses" share a few properties with their parent class "publication" and with each other, they're all still somewhat different.
That's where inheritance comes in handy. You see, if book-IS-A-publication, and magazine-IS-A-publication, then we can use inheritance to help us create our model for these two classes. This is where people get confused, though, too. Because often people confuse IS-A with HAS-A (like... car-HAS-A-tire, HAS-A-door, etc.) and overuse inheritance where it's not appropriate. The ONLY time you should be setting up classes and subclasses is when you're sure it IS-A-good idea.
[NOTE: I'm going to stick another term in here. I can cover it in more detail later but I want to introduce it here because it's germaine to the overuse of inheritance. In OO parlance, the IS-A operator specifies inheritace, while HAS-A indicates composition. Where IS-A objects inherit their parent class's methods and properties, HAS-A classes, or "composition classes" incorporate the functionality of other objects into their own instance data via get and set methods. Depending on how this is implemented, you could use the Class Explosion Design Pattern, but then someone would just have to clean up the mess, and that's nasty...]
I'm going to point out that these examples are extremely over-simplified. Don't complain, it's for your benefit. I'm more concerned that you get the idea than that I create a library management application.
Let's recap the Constructors concept. If you look back at publication.cfc, you'll remember that it has an init("pubName") method. To actually use publication.cfc in a CFM page, we would do this:
And now we see how to create an "instance" (myPub) of a "class" (publication.cfc) and use the get/set methods (init uses setName to pass an argument into instance data, getName is used in the page to extract it) to move data in and out of an object.
An "object," incidentally, is halfway between an instance and a class... instances are specific objects, like myPub, which have specific data in them at any given point in time (which is why it's important to use init() right away). Classes are, in CF terms, a CFC file. Write the CFC and you have a class. use createObject to create a variable that contains the functionality of that class, and you have an object. Use the init method to initialize the object with data, and you have an instance.
So, what does inheritance have to do with anything? Here we go... a new file... magazine.cfc!
You should notice something strange, right away. Look at the init() method... it calls super.setName() and setGenre(). Now look at the other methods. setGenre's there... as is getGenre, as you would expect. But... where did getName and setName go? When Magazine.cfc calls super.init("pubName"), instance data is set in the parent object (or, in other words, there's an implicit instance of the parent class created).
Since magazine-IS-A-publication, and our cfcomponent tag tells us that "magazine extends publication," magazine has direct access to getName and setName as if they were right there inside the CFC file. We can add functionality to magazine.cfc, and we can use publication.cfc's functionality as well. Or, in OO terms, because magazine "inherits" from publication, we can simply "extend" it by adding methods, without having to re-type all of publication's content too!
One important note: Our magazine calls it's parent class... but keep in mind that the parent knows nothing of the child. The child knows that it has a superclass, but that's it. In terms of inheritance, no parent object should know about its descendants, and a child object should only know about it parent. It is therefore important to create your objects so that their inheritance properties are handled correctly. In the end, this allows us to do is further our aims of encapsulation, cohesion, and low coupling by utilizing code we've already written -- allowing that code to do it's job and only that job.
NICE!
One more example... book.cfc:
And now we have another example of inheritance. since Book-extends-Magazine-extends-Publication, getName is inherited from publication and getGenre is inherited from magazine. It's a cumulative process, you see, and the deeper our model goes, the more things can inherit from simpler objects above them in the heirarchy.
If you're wondering about the super.init() calls, it's a matter of convention. Since I'm instantiating an object, I'll use the init() methods of it's parents so that I'm consistent. If you look at book.cfc's constructor, you'll see that I'm passing in three parameters and two of them are passed to super.init(). If you look at magazine's init() method, it takes two arguments... so book is using magazine's constructor to set up that portion of its instance data, rather than rewriting the whole constructor for this particular object.
If you look at magazine's call to super.init(), it passes one of its two arguments back to publication, which uses it's own setName method to finish the process. This process of re-use is what OO's all about.
* Book: 3 args passed in, 2 go to super.init()
* Magazine: 2 args passed in, 1 goes to super.init()
* Publication: 1 arg passed in, uses the setName method to put it into instance data
And, just for fun, check out the example below for a usage lesson:
As I said before, inheritance preserves the cohesive nature of our objects by letting code that we've already written handle the data it should while expanding on it to provide more functionality. But there's one other imporatant OO point I want to cover. That's called "abstraction."
Why would a book inherit from a magazine? It might not, and as our model grows, we might well change that. But to our understanding of the relationships between data and structure, book is more complicated than magazine, and magazine is more complicated than publication. Since they all have an IS-A relationship with each other, we don't really care about the real-world relationships between book and magazine publishers. What we care about is how they relate to eachother on a structural level inside the application. That way, we're not bounded by artificial separations or human emotion, and we can design a system that is efficient, straightforward, and fairly easy to maintain.
OO is all about design, and much less about functionality. Anything can be functional for a particular purpose. OO doesn't really care about how it works. It cares about designing systems that lay out all the relationships between entities. In other words, book inherits from magazine inherits from publication because that's how the DATA needs of the objects fall into order. We structure our models around the entities they represent, and we use inheritance or composition as best fits the needs of the moment. There is no such thing as a "correct" model... simply a "less-wrong" model, and as our understanding of those relationships expands, our model grows more and more correct.
Just remember, as you're modeling your systems... whether you're doing an online shopping site or a simple website for your in-laws vacation photos (umm... yeah, right... HAH!), what matters is an appropriate view of the larger system broken down into bits that only do one thing (high cohesion), and that can do them all alone without having to ask anyone for help (low coupling).
Our next segment will be all about Polymorphism. And no, it's not some strange medical condition.