Introduction
The relationship among classes is one of the fundamental activities of software design. There are two ways to relate classes: inheritance and composition.
Inheritance
Inheritance enables us to create a new class that reuses and extends behavior from another class called a base class or superclass and the newly created class is called the derived class. When we inherit a class from any other class, the derived class implicitly gains all the members of the base class except the constructors and destructor. So, the derived class can reuse a base class method and property without re-implementing it. In other words we can say, using inheritance, a derived class extends the base class functionality. The main advantage of inheritance is the reusability of the code. The other main advantages of class inheritance are, it makes it easy to modify the current implementation of the base class by just overriding an operation within the derived class. The limitation with inheritance is, we cannot change the implementation of the base class at run time.
Inheritance is a hierarchical relationship between classes. Inheritance can denote a "is - a" relationship between classes.
Inheritance is sometimes said to provide "weak encapsulation," because if you have code that directly uses a derived class then that code can be broken by changes to a base class.
An inheritance relationship between base classes and derived classes is often said to be fragile, because small changes done in the base class can ripple out and might require changes in many places within an application.
Example of Inheritance
public class BaseClass
{
public string property { get; set; }
public void BaseMethod()
{
// Do something....
}
}
public class DerivedClass : BaseClass
{
public string DerivedclassProperty { get; set; }
public void DerivedMethod()
{
// Do something....
base.BaseMethod();
}
}
In this example DerivedClass is related to the BaseClass by inheritance, here BaseClass is a superclass and DerivedClass is the subclass.
Composition
Composition is the most commonly used relation in a class diagram. In general terms, composition allows a class to contain an object instance of another class. Composition can be denoted as being an "as a part" or a "has a" relationship between classes.
In the composition approach, the derived class becomes the front-end class and the base class becomes the back-end class. The composition approach provides stronger encapsulation than inheritance, because a change to a back-end class does not necessarily break any code that relies on the front-end class. The main advantages of composition is, with carefully designed interfaces we can change references of back end classes at runtime.
Example of composition
public class FirstClass
{
public string property { get; set; }
public void FirstMethod()
{
// Do something....
}
}
public class SecondClass
{
private FirstClass firstClass = new FirstClass();
public string ClassProperty { get; set; }
public void MyMethod()
{
// Do something....
firstClass.FirstMethod();
}
}
In this example SecondClass (also called the front end class) is related to FirstClass (also called the back end class) by composition. SecondClass has an instance variable that holds a reference to a FirstClass object. In the composition, the front-end class holds the reference of the back end class as an instance variable.
Inheritance VS Composition
Inheritance |
Composition |
In inheritance, there is an image of the base class in the derived class object, so the image of the base class is created when the derived class object is created. |
Composition allows late creation of the backend class object until and unless they are not really required. |
Base class remains a part of the derived class object throughout the life of the derived class. |
In composition, life of the backend class is independent and we can change back end object dynamically. |
Inheritance is static binding (compile time binding) |
Composition is dynamic binding (run time binding) |
Inheritance can denote an "is - a" relationship between classes. |
Composition can be denoted as being an "as a part" or "has a" relationship between classes. |
Inheritance comes with polymorphism. |
NA |
In inheritance, there is a single invocation of an inherited base class so there is no extra cost for invocation. |
The explicit method invocation (forwarding or delegation) has a performance cost (note that performance depends on many factors). |
A change in the base class interface cannot ripple down the inheritance hierarchy to a derived class. |
It is easy to change the interface of a back-end class and front-end class |
In inheritance, it is not required to implement all base class methods within the derived class. |
In composition, all methods provided by composed classes must be implemented in the front end class. |
The derived class and base class interfaces are tightly coupled. |
The front-end and back-end interfaces are loosely coupled. |
It is easier to add new derived classes in inheritance than to add new front-end class in composition.
Conclusion
The inheritance model is denoted as being an "is - a" relationship and composition is denoted as being a "has - a" relation ship between classes. The developer is always confused, choosing between inheritance and composition. Do not use inheritance just for code reuse. If there is no is-a relationship between classes then use composition. Do not use inheritance to get polymorphism. We can use inheritance to express differences in behavior and fields to express variations in state in a state design pattern.