Why Kotlin Favor Composition Over Inheritance
Discussing Kotlin Interface delegation and the shortcoming of the implementation inheritance
Filter by Category
Filter by Author
Discussing Kotlin Interface delegation and the shortcoming of the implementation inheritance
Posted by Baraa Abuzaid
The adapter design pattern is a structural design pattern that's very useful when maintaining a legacy code or adding a new features.
Posted by Baraa Abuzaid
The Façade design pattern is a structural design pattern. It reduces coupling and improves code readability.
Posted by Baraa Abuzaid
Will be going through the Creational Design Pattern illustrating how and where to use it.
Posted by Baraa Abuzaid
This tutorial will explain the fundamentals of ViewModel and LiveData and how to use them by creating simple demo App that shows recent movies.
Posted by Baraa Abuzaid
This is a brief look into MVP clean architecture discussing why it is the best architecture for android development
Posted by Baraa Abuzaid
This tutorial will illustrate how to implement infinite scrolling in Android, where the data should be load automatically as the user scrolls down
Posted by Baraa Abuzaid
Example that goes through making a UML class diagram from simple problem statement
Posted by Baraa Abuzaid
This is a part of a blog series that will go through all you need to know about UML class Diagram to get up and running quickly
Posted by Baraa Abuzaid
Discussing Kotlin Interface delegation and the shortcoming of the implementation inheritance
For starters what is composition and what is inheritance? A simple way to explain that is to say the Composition is when you design your object around what they do, and the Inheritance in when you design your object about what they are. Despite the fact that implementation inheritance sometime might get you into thinking that you are doing the most elegant design, it comes with a huge package. Because at the beginning of any project most of the time you really don’t have a vivid idea of exactly all classes and relation between them are going to be. And soon you start building your design around assumptions that might change at any point in the future. Making your beautiful design built upon Inheritance fall apart.
I think Mattias Petter has put it so nicely in his video composition over inheritance I really recommend watching.
Let’s continue our discussing on the inheritance shortcoming by taking a look at this example. suppose you are extending HashSet adding some sort of counting that increments whenever a new item is added to the set.
class MyHashSet:HashSet<Double>() {
var count:Double = 0.toDouble()
override fun add(element: Double): Boolean {
count +=1
return super.add(element)
}
override fun addAll(elements: Collection<Double>): Boolean {
count += elements.size
return super.addAll(elements)
}
}
fun main(args:Array<String>){
val myHashSet = MyHashSet();
myHashSet.add(1.0)
myHashSet.add(2.0)
myHashSet.addAll(listOf<Double>(3.0,4.0));
println("total number of the elements in the set = ${myHashSet.count} ")
// out put :>> total number of the elements in the set = 6.0
}
Surprisingly running our MyHashSet
get us a wrong number of elements count. and that’s because internally the method addAll()
uses add()
. resulting in add()
being called twice when using addAll()
and instead of getting 4 we get 6.
off course we could change how MyHashSet
do counting and remove the incrementation from addAll()
method. But, that’s still not a good object orientation. And the very fact that I still need to check how the class been implemented internally, reject strong point in good object orientated programming, the idea that all object should be treated as a black box and used easily without the overhead of knowing the detailed implementation.
Using compostion intead of inheritance will be a good idea to avoid such outcome. and in doing so programming language like Kotlin provides a handy features.
Kotlin does favor composition over inheritance by cutting off all the boilerplate using interface delegation.
interface IManager{
fun plan()
fun work()
}
open class SalesManager:IManager{
override fun plan() {
println(">> I do planing")
}
override fun work() {
println("I work at Sales Department")
}
}
// one line composition through interface delegation
class Supervisor (manager:IManager): IManager by manager
fun main(args:Array<String>){
val supervisor = Supervisor(SalesManager())
supervisor.work()
}
As you can see we have SalesManager
class that implements IManager interface. Furthermore, we also have Supervisor
class that needs to do the same work that SalesManager
class do. So, instead of having duplicate code or doing inheritance, we could reach the desired result through composition. Looking at the following line
class Supervisor (manager:IManager): IManager by manager;
We can forward any calling to the method plan()
or work()
to the SalesManager
class. All by using the by
clause which indicates that manager
will be stored internally in object of Supervisor
and the compiler will generate all the methods of IManager
that forward to manager.
Now let’s have a look at how we could achieve the same result in Java.
public interface IManager {
void plan();
void work();
}
public class SalesManager implements IManager {
@Override
public void plan() {
System.out.println(">> I do planing");
}
@Override
public void work() {
System.out.println("I work at Sales Department");
}
}
public class Supervisor {
IManager manager;
public Supervisor(IManager manager) {
this.manager = manager;
}
public void work(){
manager.work();
}
public void plan(){
manager.plan();
}
}
public class Main {
public static void main(String[] args){
IManager manager = new SalesManager();
Supervisor supervisor = new Supervisor(manager);
supervisor.work();
}
}
Clearly, Kotlin nailed it by cutting off a lots of boilerplate. This might look trivial in this example but, imagine in a large project how Kotlin approach will be pretty handy and will get you as well into favoring composition over inheritance.
Photo by Ricardo Gomez Angel
If you like me you probably have heard of Kotlin, but you have been resisting its temptation. I kinda of understand that. You have all of those shiny cross-platforms framworks to...
A Proxy design pattern is a structural design pattern. the idea behind is to make a proxy object that is capable of performing tasks similar to the original object. The need for...
In java version, why Supervisior doesn’t implement IManager. Thanks in advance.
Hi Aung,
Yes, here in this example you could. but I just want to demonstrate how Kotlin Interface delegation
would like if we are about to do it in java. since java interfaces prior to Java 8 can’t carry any default implementation.
But, You might imagine a case where a class like SalesManager that implements IManager Interface carries lots of
implementation details and it comes from a third-party library, and you don’t want to go through the hassle of reimplemented yourself.
Hi Baraa, thanks for this article!
As a reader i expected to see first example written in kotlin but with composition. Second example just showing that kotlin can reduce boilerplate that java has.