Sunday, September 9, 2007

Favor Composition (“has a”) over Inheritance (“is a”)

!!! Composition and Inheritance should complement each other !!!

The important key words of any object oriented programmer is “is a” and “has a”. These two key words relate an object with another object. For example, in a real world a “Human” and “Man” is a relationship. “Human” and “Hands” have “has a” relationship. In short, “Man” is a “Human” and “Human” has hands. Inheritance is a great tool that helps to define hierarchy and model concepts as real world objects. It also reduces greater amount of code through code reusability. But in normal scenario, composition just helps up to model objects as they are. For example, Earth has continents, Continents have countries, countries have states, states have cities/towns/villages and goes on. Here the composition is typically used for the relationship “has”. Traditionally, when one wants to implement a function, a method will be added. But composition can be used in an extraordinary ways to bring in dynamic behavior in the system. The composition makes the software flexible and it gives different dimension to object oriented programming. Let us quickly get into some action with an example.

You need to implement different types of sorting algorithm. But there are many sorting available and you should implement bunch of them. Based on the client requirement, you need use any one of the sorting algorithm (when there is low memory, you need to go for insertion sort but if the memory is high you can go for quick or merge sort). The bottom line is the client knows which algorithm is needed and your framework has to do the job. If the memory is low, the clients decide to go with insertion sort and the framework needs to use the sorting algorithm. Also, if the client is interested, the client should be able to fit in their own algorithm “weird sorting” into your framework. How will you go about with this problem? How will you design classes?

There are two ways of solving this problem. The first way is very crudest way where you have all the sorting algorithms implemented in a same class. The single class will have methods – binarySort, insertionSort, heapSort and so on. This straight away blow up the design principle – open close principle. For adding up new sorting “weird sorting”, you need add a new “weird” method. It produces a maintenance nightmare. The second way is slightly smarter way where in the sorting algorithms are implemented as class for each class inheriting from a class “Sorting” which is abstract. But the clients have to use them based on their requirement and most importantly they cannot change the sorting algorithm dynamically.

The third approach to this problem is implement an abstract class or an interface “Sorting” that has a method “sort”. Each sorting algorithm implements this “sort” method and as the result you have many sorting algorithm. When you want add “weird sorting”, it is as simple as to add new class implementing the “sort” method. Your code follows open close principle and this avoids a lot of testing. You can for sure say that your new code does not introduce a bug in the old code. So far, we talked about inheritance. This is usual stuff.

How will you allow others to invoke the sorting method? You need to extend each of the sorting class and so that others invoke the “sort method”. But this method leads to class explosion. When a new sorting is implemented, you need to change/add code. But instead of doing this, you can have the sorting algorithm as a component with a “has a relationship”. For example,

public class Client {
private Sorting sortingAlgorithm;

public void setSortingAlgorithm(Sorting sortingAlgorithm) {
this.sortingAlgorithm = sortingAlgorithm
}

public void someOperation() {

sortingAlgorithm.sort(); //first

/// some operation

sortingAlgorithm.sort(); //second
}

Consider the method someOperation() of Client class. Also assume that Client is a shared object and so many people decide on the particular sorting algorithm. Now the sorting algorithm can be changed dynamically based on various factors. If your application has memory management module, it can play its part to decide on the particular sorting algorithm. In the above example, the first method could be a different sorting and the second sorting could be a different sorting. This, what we mean by flexibility.

In order to engage people in using composition, most developers argue the words “Favor Composition over Inheritance”. These words are simply phrased to give you the power of composition. These words should not be taken literally and no composition works greatly without employing inheritance. So both “Composition”and “Inheritance” should complement each other in a true object oriented perspective. It is time to etch

!!! Composition and Inheritance should complement each other !!!

No comments: