Composition over the inheritance

design-pattern.png?w=2924

The Story

I recently encountered a question about why it’s better to using interface than inheritance. I have this because we defined lots of interfaces (behaviors) in a recent project. And, I am not saying this is bad, but just because this is not my familiar pattern when trying to design a system and also wanted to think of it deeper why we are doing that. I am confused if some classes share the same behaviors, my first thought from Java world is to create a parent class to define those common behaviors and then derivative classes would get the benefits without implementing the same behaviors again. But someone told me: Using an interface is better. So, I want to figure out why an interface is better than inheritance. According to the wiki description:

Composition over inheritance - Wikipedia
Composition over inheritance (or composite reuse principle) in object-oriented programming (OOP) is the principle that classes should achieve polymorphic behavior and code reuse by their Composition (by containing instances of other classes that implement the desired functionality) rather than inheritance from a base or parent class

Composite Reuse Principle

Yes, that’s also called composite reuse principle. So, the relationships of inheritance and Composition are referred to as IS-A and HAS-A relationships. Then why should we use the composition pattern (Interfaces) more?

  1. Flexibility of reuse
  2. More precise and readable logic.
  3. Easily create test cases for components.

Let’s check an example about the inheritance. You need to remember that’s an IS-A relationship.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
open class Dog {
fun bark() {
println("Bark!")
}
}

class GermanShephard : Dog()
var myDog = GermanShephard()
myDog.bark()
```

It's fundamental. Let's create a parent `Dog` class with a function called bark. Every derivative class, for example - GermanShephard, would be able to bark because a german Shephard is also a kind of dog (`IS-A`). It looks very reasonable. Let's add another dog - Belgian malinois, and let these two dogs learn another skill - sniffing drug.

#### Define more behaviors by inheritance

open class Dog {
fun bark() {
println(“Bark!”)
}
}

class GermanShephard : Dog() {
fun sniffDrugs(drugs: Objects) {
if (drugs != null) bark()
}
}

class BelgianMalinois : Dog() {
fun sniffDrugs(drugs: Objects) {
if (drugs != null) bark()
}
}

class Poodle: Dog()

1
2
3
4

Well, it still looks reasonable so far, because both german Shephard and Belgian malinois are used to be trained to execute this kind of tasks and they can do this very well. And also, a poodle is a kind of dog, no question about that. From the inheritance point, we usually put the redundant code to parent class, that's a pretty straightforward mindset (I am doing in this way). Let's put the function `sniffDrugs` into parent Dog class. Then, you might find something wrong.

#### Something wrong?

open class Dog {
fun bark() {
println(“Bark!”)
}

fun sniffDrugs(drugs: Objects) {
if (drugs != null) bark()
}
}

// Does a poodle can do sniffing drug work?
class Poodle: Dog()

1
2
3


Can a Poodle be trained to sniff drugs? Maybe! But in our example, it seems to be wrong cause a Poodle can't have this skill. How to solve this? Maybe creating another SniffTrainingDog class is a solution? Let's see.

open class Dog {
fun bark() {
println(“Bark!”)
}
}

open class SniffTrainingDog: Dog() {
fun sniffDrugs(drugs: Objects) {
if (drugs != null) bark()
}
}

class GermanShephard : SniffTrainingDog() { … }

class BelgianMalinois : SniffTrainingDog() { … }

class Poodle: Dog()

1
2
3
4
5
6

You can find a fact: when we need more behaviors, and those behaviors show the conflict, then we would need more parent classes to contain and define different behaviors. That makes the project a mess, and it's not a good design.

#### A clean and simple solution

Ok, it's time to try Composition now to clean the design. It looks much better when we add more behaviors for derivative class. You can define several behaviors that a dog can do.

interface Barker {
fun bark()
}

interface Swimmer {
fun swim()
}

interface DrugSniffer{
fun drugSniff()
}

class GermanShephard: Barker, DrugSniffer {
override fun bark() { … }
override fun drugSniff() { … }
}


That would be easier to test and define what a german Shephard can do. Is the inheritance dead, and we can't use it anymore? No, I don't think so. I think we should carefully choose the design pattern before we start a project. 


Happy coding, enjoy. 




#### [Reference]

1. [Composition over inheritance - Wikipedia](https://en.wikipedia.org/wiki/Composition_over_inheritance)
2. [Composition over Inheritance - Fun Fun Function - Medium](https://medium.com/humans-create-software/composition-over-inheritance-cb6f88070205)
3. [Interfaces vs Inheritance in Swift - Mike Buss](https://mikebuss.com/2016/01/10/interfaces-vs-inheritance/)
4. [Protocol-Oriented Programming in Swift - WWDC 2015 - Videos - Apple Developer](https://developer.apple.com/videos/play/wwdc2015/408/)
5. [OO Design Patterns: Composition Vs. Inheritance - The Startup - Medium](https://medium.com/swlh/oo-design-patterns-composition-vs-inheritance-4206a6b018bb)