I tend to favor object composition over class inheritance. This is especially true when I’m modeling a business process because business is about distinct people coming together to produce a particular result.
Organizations have hierarchy. Yet, that “coming together” is typically more functional than hierarchical. One can say teams are “composed” of distinct functional specialties (Designer, Developer, UX, etc.) and so a modern composite approach to object oriented programming lends more naturally to the way work actually gets done.
But, I wanted you to understand class inheritance is only one approach to object oriented programming. Better yet, I want you to see examples of how others use both the object composition and class inheritance techniques.
For example, I find class inheritance particular useful when modeling a distinct real world object. On the flip side, I find object composition works great when modeling Line of Business applications and other games.
Modeling Buttons, Bases and Shiny Things
Take the power panel for example:
In particular, let’s focus on two components of the power panel:
In classical object oriented fashion, you’d reason both the Light and the Button share a base each uses to embed itself within the power panel. From there both the Light and Button would go on to have distinct properties and methods.
There are a couple of really cool things at work here. Let’s take some time to look at each.
First, you’ll notice the class is defined using an anonymous self executing closure which returns its class signature after it is defined. The closure encapsulates the details of the class. But, it also turns the class signature into a kind of namespace, thereby preventing class properties and methods from polluting the Global Namespace.
Second, you’ll notice the class has a bonafide constructor you can use to setup the class instance. All methods of the class extend the prototype chain of the class: Class.prototype.* Lastly, we return the class definition - it will be your class’ interface to the world.
You could easily create a new instance of the base class:
But, that wouldn’t be too useful. And that’s fine because it’s not meant to be too useful. The base class is just that, a base class (with base functionality) from which most other classes will inherit from. Here, the base’s primary function is to simply drawTerminal because everyone will need a Terminal in order to connect to the Power Panel.
Things really get interesting when you want to create a Light that inherits from the base class. But, what’s the best way to accomplish classical inheritance in a prototypical world?
The first thing you’ll notice is we passed the parent class into the self-executing closure. This then becomes the super object reference in the anonymous function. The parent constructor and methods are access through the super object.
In particular, to call the parent’s constructor, simply execute:
Function.call calls a function with a given this value and the arguments provided individually. You can use call to chain constructors for an object. Here, this refers to the current object, the calling object. Next, you can supply as many arguments as your parent’s constructor demands.
Access to the parent’s methods are done through the prototype chain:
All the things that make your code more maintainable.
CoffeeScript: In Too Deep
Still with me? Excellent!
Up until this point, your freshly minted Light Class can call it’s parent constructor and call methods on its parent class. But, you haven’t actually inherited anything.
That is to say, the methods of the Base Class are not present on the prototype chain for the Light Class.
If inheritence worked, the Light Class would have four methods on the prototype chain. Two from the parent: drawTerminal and getId. The remaining (from itself): setColor and getColor.
Yet, only the Light Class methods exist:
Not a complete loss. You could still write wrappers over the parent methods. After all, you still have access to _super. But, for large code bases, this can become unmaintainable. Better if child instances just magically had access to parent methods.
That’s where CoffeeScript’s Extends method comes into play:
CoffeeScript Extends method does a deep copy of parent methods unto the child prototype chain. Even better, using CoffeeScript Extends method is easy. Simply pass the child class as the first argument and the parent class as the second argument:
The result is parent methods are accessible in the child class without having to rewrite those same methods:
This time when we count we get the four expected methods: drawTerminal, getId, setColor and getColor. Which is great because an instance of the child class can access the parent method with ease:
This cuts down on the potential for much code duplication. Also, it’s simply pleasant to use. You still call the parent constructor using the _super.call route. But, this time you can access the parent methods within the current scope. Lastly, instances of the Light class magically have access to those parent methods as well.