Inheritance and composition are useful concepts in oop , but there is a dilemma whether to use inheritance or composition in some instances.The use of inheritance is mainly for gaining a particular type of behavior. But composition is mainly used to give particular functionality.
In the above diagram, Doctor is a person. So we could say that the person has the behavior of a person. A person can show movements and so does a dog. But we never say Dog is a person. because the dog as a whole does not have the behavior of a person. But it has the functionality of being able to show movements. So how to handle that without re-implementing some code that provides similar behavior. Basically similar kind of code with slight modification. In object oriented paradigm we try to implement structures that are reusable in effective ways.
One way of letting code to be reused is to reuse methods already implemented inside super classes, which is considered bad.
Following are the reasons that it is considered to be bad.
- The base class becomes fragile.
- The concrete classes become more tightly coupled to the base class
- Through protected variables and some non private methods the encapsulation gets violated
- Deep hierarchies may be affected massively by a slight change in the base class(fragile)
But we still need inheritance. When we use inheritance, we shouldn't use it for mere code reuse, but to gain the overall behavior of the parent class.
So in the above example the Dog is not a person. But the dog needs the functionality of making movements. For that purpose we can implement the showing movements functionality under a different abstract class and give the reference of that abstract class into both Person and Dog classes using common interface defined in abstract class. Under that abstract class we can make two concrete classes as one implements the behavior of a person movement and the other implementing dog movement.
The diagram is as follows.
So one advantage that we gain by using composition for giving functionality is to flexibility of changing the functionality dynamically. For example if we needed to give a different behavior to the person's movement, then we can dynamically change the assigned object for the abstract class's reference under the Person class. Encapsulation is also preserved because from Dog class or Person class only a defined set of methods under the abstract class is visible to those two classes.
Another example can be said as following,
Assume a book(a diary) which is currently available to write and read both, but in the future it will become read only when all the pages are written.
In this scenario, the book will be a non writable after sometime. but in the program how to change the existing book object into a non writable book object. Since the functionality changes due to the type of the book, several functionalities have to be changed dynamically.
if we used following architecture with inheritance,
Then we will have to copy all the object state variables into a new object of type non writable book. Which doesn't look good in first hand. And on the other hand it is a costly operation.
But we also can use following structure with composition.
In here if we want to change the books state into non writable, all we have to do is dynamically allocate a new object of non writable functionality to the reference in the Book object. So from the Book class the same methods are called through the abstract interface, but now a different functionality is implemented by the underlying object.
So the developers prefer composition over inheritance due to these kind of reasons. Through inheritance, we extend the existing behavior using a sub class. We make it more concrete than generalized. Through composition, we delegate some functionality under a particular module. So the coupling is reduced, because the calling class does not see the underlying complexity of the delegated class other than the methods provided in the abstract class. So if a change happens inside or any variable names changes it does not affect the class that uses it. In this case we can talk about the cohesiveness of the of the delegated class. But since its another broader topic, I will talk about cohesiveness in another article.
So lets take our first example. The Doctor is a Person. But it's just a role played by the person. Depending on the program's approach and scope, the person will act some other roles like being a lecturer(Like in a social builder game). So you will need to change the role of the person dynamically. So you can take the approach as giving the Person a role as a variable reference inside the class and dynamically allocate different roles to the Person's role variable.
So depending on the scenario, we have to choose between inheritance or composition. In some instances, inheritance might be suitable and sufficient. But sometimes using composition might come in handy.
We say that oop is basically about representing real world objects in programming objects to make beginners understand the paradigm. But when you gain experience, do not do designs keeping that in mind, as it might unknowingly lead you into some bad designs. Always try to stick to the best practices.
Comments
Post a Comment