last edited byusericonadmin on 29-Apr-2010

Contents

Inheritance

Inheritance is an object oriented technique that allows you to re-use code across related objects in your applications.

Imagine you have an application that contains both teachers and students. In a very simplified application our teacher and student may look something like this:

A teacher has a name and a set of students.

A student has a name and a set of grades.

We can see that both Teachers and Students have setName() and getName() functions. The code for these functions are identical in both components so it would be good if the code could be shared.

With inheritance we move shared code into a separate component. In this example we can create a Person object that contains the shared setName() and getName() code:

Now we need to indicate that the Teacher and Student components are particular kinds of "extensions" of the Person component.

In CFML we use the "extends" keyword on the component tag.

<!--- Person.cfc --->
<cfcomponent name="Person">
    ...
</cfcomponent> 

<!--- Student.cfc --->
<cfcomponent name="Student" extends="Person">
    ...
</cfcomponent> 

<!--- Teacher.cfc --->
<cfcomponent name="Teacher" extends="Person">
    ...
</cfcomponent> 

In UML this is represented as:

The UML diagram here shows empty arrow heads, which indicate "inherits from". So we can say that Teacher inherits from Person and Student inherits from Person.

In CFML nomenclature, the Person component is referred to as the "parent-component" or "super-component". The Teacher and Student are the "sub-components"

With inheritance, the subcomponents automatically get a copy of any functions in their parent components. With this approach we can write code such as:

<cfset teacher = createObject("component","Teacher")>
<cfset teacher.setName("Spock")>
<cfoutput>
    #teacher.getName()#
</cfoutput>

Inheritance can extend as deep as required. For example if we needed to introduce a new HeadTeacher into the system, then the HeadTeacher could extend the Teacher component.

The CFML code for our head teacher would look like:

<!--- HeadTeacher.cfc --->
<cfcomponent name="HeadTeacher" extends="Teacher">
    ...
</cfcomponent> 

Each HeadTeacher object would have its own getStaff() function, but would also inherit the getStudents() function from Teacher and the getName() and setName() functions from Person.

Inheritance is more than just code sharing

Inheritance provides a mechanism for sharing code across components, but it also has a special meaning in object oriented design and should typically not be used as a widespread code sharing technique.

Inheritance implies specialisation

This means that when you are travelling down the inheritance hierarchy, each component further down should be a more "specialised" version of the one before it:

Conversely, as you travel up the inheritance hierarchy, each component further up should be a more "generalised" version of the one before it:

Inheritance is an "IS A" relationship

There is a simple way to test if you have proper inheritance; you should always be able to say that your sub-component IS A super-component.

Looking at our example we can say:

Example of bad inheritance

Suppose you have an object that calculates prices including tax for you.

Then elsewhere in your application you have a Product object that needs to use this calculation function.

It would be incorrect usage of inheritance to have your Product inherit from the TaxCalculator.

Applying our IS A test to these components:

"Product IS A TaxCalculator"

Not really. Our product needs to use a tax calculator, but is it not a calculator itself.

In cases such as these there are other techniques for sharing code across components such as composition which we will discuss shortly.

Guidelines for good inheritance implementations

Keep lightweight parent-components

Components higher up in the inheritance hierarchy should be kept as "lightweight" as possible. This keeps their meaning very specific and single purposed.

If a parent component has many functions then a sub-component may inherit functions it doesn't need. If this happens it could be a sign that:

  1. the parent component is doing too much, or
  2. the sub-component is not really a specialisation of the parent and should not inherit from it.

Keep a strong relationship with parent-components

Your sub-components should have a strong relationship with the parent component. This is related to the previous guideline in that all of the parent functions should be directly relevant and useful to the sub-component.

Avoid sub-component combinations

Suppose you have a component Ball, and you create three sub-components BouncingBall, FlashingBall and SpinningBall. You then find that you need balls that are combinations of the other three sub-components; a BouncingFlashingBall, a BouncingSpinningBall, a FlashingSpinningBall and a BouncingFlashingSpinningBall.

This leads to a very messy implementation particularly as each new Ball sub-component is created.

In cases such as these, where you appear to need multiple combinations of sub-components then inheritance is not the best choice. It is better to use an alternative technique such a Decorator design pattern rather than inheritance.

References

CFML References

The Pain of Inheritance

Using Inheritance and Composition in ColdFusion Components

Inheritance and composition in ColdFusion 9

Other References

Inheritance-oop

Yo-yo problem

Bank Example with Inheritance

Stack Overflow: What's a good example for class inheritance?

Inheritance (object-oriented programming)

Inheritance is evil, and must be destroyed: part 1

Object Oriented Inheritance