It all start with resolving the code duplication issue. The concept was pretty straightforward. Write the code once and use that code everywhere when needed. Why not! Who wants to write the same code multiple times. After all the duplicate code is a nightmare for code maintenance. So Inheritance was introduced.
Introduction
So we were given a new concept of Inheritance. On initial state it seems very awesome to write down the code on Inheritance patterns, but after some times when the code base grows that Inheritance code start to shape like a Spaghetti code. If one portion is modified the others portion falls. Overall it becomes very tough to understand the code base and to debug the falling part of the code base. Now again it is a nightmare for code maintenance, but this time a more complex one. Did it really help us? Or the Inheritance just put us on a more difficult situation?
If we try to avoid the Inheritance patterns, then what options do we have here on Swift? Well, there is one cool solution and that is the Protocol. On protocol oriented programming we will be using composition patterns for handling the duplicate code. The composition patterns is not something new, but it is not yet that much popular as Inheritance is. But day by day we are getting more closer to composition than the Inheritance.
The concept Protocol is also not new to iOS development, but now on Swift the protocol has some real cool features which facilitate the developer to achieve the composition, dumping the inheritance.
The Swift Protocol Hub contains all the related post with protocol. Be sure to check that out.
The dilemma
Does that mean we will not use the Inheritance at all. No at all. We have to use Inheritance also, it has its benefit. And we have to know the ins and outs of Inheritance and Composition.
There is no silver bullet to this problem. What we have to achieve is the balance, probably a bit more lean to Composition rather than the Inheritance. Let us use this talk on this topic. This will be the very first blog post of six blog post series to teach ourself about Composition over Inheritance and when to choose which one.
Background
What is Inheritance
On Inheritance patterns we will have a base class. And that base class will hold all the common property. And then the derived class will inherent the properties from the base class, plus they will add their’s own property.
Anything that is common will move to base class, so that all the derived class get that property from base class, this will remove the duplicate functionality from the code base. Let us have an example.
We need to use class whenever we want to establish some Inheritance on our code base. Value type like enum
and struct
can not establish an Inheritance as class
can. We will talk about this topic on the next blog post.
This time we will derived some superheroes from DC comics. Lets build Justice league 😉. So our base class will be SuperHero
and from the SuperHero
we will start building the other derived class, like Batman
, WonderWomen
etc.
class SuperHero{
let name: String
let originalName: String
let capeColor: String
init(name: String, originalName: String, capeColor: String) {
self.name = name
self.originalName = originalName
self.capeColor = capeColor
}
func speciality() -> String{
return ""
}
var profile: String?{
return "Known as: \(name) \n Original Name: \(originalName) \n Wears a \(capeColor) colored Cape.\n Speciality is: \n\(speciality())"
}
}
So here is our SuperHero
class. We have some common property like name
, originalName
and capeColor
listed here. We have a method named speciality
which currently returns an empty String
as the derived class will override this method according to their needs. Because each of the derived super hero will have their own speciality. Finally we have a computed property named profile
which will print all the details of the specific super hero.
As we know the very first founding member of Justice League was Batman
and WonderWoman
. So let us build that two class from the base class SuperHero
.
class Batman: SuperHero{
init() {
super.init(name: "Batman", originalName: "Bruce Wayne", capeColor: "Black")
}
override func speciality() -> String {
return "Very techie and extremely cool 😎"
}
}
class WonderWoman: SuperHero{
init() {
super.init(name: "Wonder Woman", originalName: "Diana", capeColor: "Red")
}
override func speciality() -> String {
return "Come on, she is a Demigoddess"
}
}
On the above two derived class, Batman
and WonderWoman
, we defined the properties like name
, originalName
and capeColor
on the respective init()
. Also we override the speciality()
method to provide the corresponding power description.
As a result by using the Inheritance we were able to override the property/function, speciality()
, that was different for different derived class. Also we pushed the profile
var up to base class, SuperHero
, to remove the code duplicity.
Benefit of Inheritance
- Common code on base class, reduction of duplicate code
- Reusability, as derived class just inherent all the property and methods from the base class.
This benefits seems very ok on the first look. But those benefits will bite us on the long run.
As we all know Software need to be updatable/ modifiable. So there should be changes upcoming.
In that respect, we need to build our software in such a manner so that we can deliver the latest requirements by doing minimal changes to your code base. This means less coupling of our code. Does Inheritance help us anyway on this purpose or does it make our code base more coupled.
Drawback of Inheritance
As we know after Batman
and WonderWoman
, The Flash
joined the Justice league. So let us make a new derived class TheFlash
.
But immediately we find out that TheFlash
does not have any cape, so there is no capeColor
for TheFlash
. Hmmm…
Inheritance already bite us. The structured code of Base class, SuperHero
, makes a tight coupling with capeColor
. We can not modify this the capeColor
to nil without modifying the structure of the base class, SuperHero
. And already we have two derived class dependent on this base class. On production it cloud be some very significant number of derived class. Updating all of them can easily lead us to some serious bugs.
When we initiate the Inheritance for our code base, we though Inheritance will save our development time by reducing the duplicate code. And on initial stage it does. But things are getting messy when we have some new requirements. Now we need to change the base class and all the derived classes, which cloud easily lead to a 100 classes or even more. This will cause us some serious development time.
Let us have a summary of the problem we face for using Inheritance of the very first hand.
- Coupling
- Development time
- Potential bugs
Now what measurement we should have taken for not leading us to this situation? The answer is Composition. We will talk more about composition on our next talk. And achieving composition through protocol on the future talks. Al always the corresponding code is pushed to GitHub.
Happy Talk.
5 thoughts on “Inheritance, Initiator of coupling”