Favor composition over inheritance is a one of the popular object oriented design principle, which helps to create flexible and maintainable code in Java and other object oriented languages. Many times I have seen people suggesting use composition instead of inheritance, in fact my favorite books like Head first Design Patterns, also advocates this design principle. Head first books, has its own way of explaining, why composition is better than inheritance and though its long its quite interesting and informative. It was the first chapter of this book, which helped me a lot on understanding this key OOPS concept. In this Java and OOPS tutorial, I have tried to summarize my experience around composition and inheritance in two main category, first, difference between composition and inheritance and second, when to use Composition over inheritance in Java. I have already mentioned about this design principle, in my list of 10 OOPS and SOLID design principles for Java programmers, here we will take a more closer look.
5 Reasons to Prefer Composition over Inheritance in Java
Just to revise, composition and Inheritance are ways to reuse code to get additional functionality. In Inheritance, a new class, which wants to reuse code, inherit an existing class, known as super class. This new class is then known as sub class. On composition, a class, which desire to use functionality of an existing class, doesn't inherit, instead it holds a reference of that class in a member variable, that’s why the name composition. Inheritance and composition relationships are also referred as IS-A and HAS-A relationships. Because of IS-A relationship, an instance of sub class can be passed to a method, which accepts instance of super class. This is a kind of Polymorphism, which is achieved using Inheritance. A super class reference variable can refer to an instance of sub class. By using composition, you don’t get this behavior, but still it offers a lot more to tilde the balance in its side.
1) One reason of favoring Composition over Inheritance in Java is fact that Java doesn't support multiple inheritance. Since you can only extend one class in Java, but if you need multiple functionality like e.g. for reading and writing character data into file, you need Reader and Writer functionality and having them as private members makes your job easy. That’s called composition. If you are following programming for interface than implementation principle, and using type of base class as member variable, you can use different Reader and Writer implementation at different situation. You won’t get this flexibility by using Inheritance, in case of extending a class, you only get facilities which are available at compile time.
2) Composition offers better test-ability of a class than Inheritance. If one class is composed of another class, you can easily create Mock Object representing composed class for sake of testing. Inheritance doesn't provide this luxury. In order to test derived class, you must need its super class. Since unit testing is one of the most important thing to consider during software development, especially in test driven development, composition wins over inheritance.
3) Many object oriented design patterns mentioned by Gang of Four in there timeless classic Design Patterns: Elements of Reusable Object-Oriented Software, favors Composition over Inheritance. Classical examples of this is Strategy design pattern, where composition and delegation is used to change Context’s behavior, without touching context code. Since Context uses composition to hold strategy, instead of getting it via inheritance, it’s easy to provide a new Strategy implementation at run-time. Another good example of using composition over inheritance is Decorator design pattern. In Decorator pattern, we don't extend any class to add additional functionality, instead we keep an instance of the class we are decorating and delegates original task to that class after doing decoration. This is one of the biggest proof of choosing composition over inheritance, since these design patterns are well tried and tested in different scenarios and withstand test of time, keeping there head high.
4) Though both Composition and Inheritance allows you to reuse code, one of the disadvantage of Inheritance is that it breaks encapsulation. If sub class is depending on super class behavior for its operation, it suddenly becomes fragile. When behavior of super class changes, functionality in sub class may get broken, without any change on its part. One example of inheritance making code fragile is method add() and addAll() from HashSet. Suppose, If addAll() of HashSet is implemented by calling add() method and you write a sub class of HashSet, which encrypt the content before inserting into HashSet. Since there are only one methods add(), which can insert object into HashSet you override these method and called your encrypt() method by overriding add(). This automatically covers addAll() as well, because addAll() is implemented using add(), it looks very enticing.If you look closely you will see that this implementation is fragile, because its relied on super class behavior. If base class wants to improve performance and implements addAll() without calling add() method, following example will break.
public class EncryptedHashSet extends HashSet{
.....
public boolean add(Object o) {
return super.add(encrypt(o));
}
}
If you have used Composition in favor of Inheritance you won't face this problem and your class would have been more robust, because you are not relying on super class behavior any more. Instead you are using super class method for addition part and you will benefit with any improvement in addAll() as shown in below example:
public class EncryptedHashSet implements Set{
private HashSet container;
public boolean add(Object o) {
return container.add(encrypt(o));
}
public boolean addAll(Collection c) {
return conatainer.add(encrypt(c));
}
.......
}
In short, don't use Inheritance just for the sake of code reuse, Composition allows more flexible and extensible mechanism to reuse code. Make sure you don't forget this rule, if you don't to do this :)
5. Another reason of favoring Composition over inheritance is flexibility. If you use Composition you are flexible enough to replace implementation of Composed class with better and improved version. One example is using Comparator class which provides compare functionality. if your Container object contains a Comparator instead of extending a particular Comparator for comparing , its easier to change the way comparison is performed by setting different type of Comparator to composed instance, while in case of inheritance you can only have one comparison behavior on runtime, You can not change it runtime.
There are many more reasons to favor Composition over inheritance, which you will start discovering once you start using design patterns in Java. In nutshell favoring Composition results in more flexible and robust code than using Inheritance. Though there are certainly some cases where using Inheritance makes much sense like when a genuine parent child relation exists, but most of time it makes sense to favor composition over inheritance for code reuse. There is an item of this topic on my another favorite book, Effective Java, which has also helped me to understand this concept better, you may want to look that as well.
Tidak ada komentar:
Posting Komentar