SOLID Principles Part-2

App Devops
3 min readSep 3, 2022

Continuation of SOLID Principles…..Part-1-https://app-devops.medium.com/solid-principles-part-1-67b244fbac06

4. Interface Segregation Principle

The Interface Segregation Principle (ISP) states that clients should not be forced to depend upon interface members they do not use. When we have non-cohesive interfaces, the ISP guides us to create multiple, smaller, cohesive interfaces.

When you apply ISP, classes and their dependencies communicate using tightly-focused interfaces, minimizing dependencies on unused members and reducing coupling accordingly. Smaller interfaces are easier to implement, improving flexibility and the possibility of reuse. As fewer classes share these interfaces, the number of changes that are required in response to an interface modification is lowered, which increases robustness.

Let’s take an example.

So let’s think that we have an animal interface. And this interface will have methods about behaviors that animals do.

interface Animal{
fun eat()
fun sleep()
fun fly()
}

class Cat: Animal{
override fun eat() {
println("Cat is eating fish")
}

override fun sleep() {
println("Cat is sleeping on its owner's bed")
}

override fun fly() {
TODO("Not yet implemented") // Cats can't fly
}
}

class Bird: Animal{
override fun eat() {
println("Bird is eating forage")
}

override fun sleep() {
println("Bird is sleeping in the nest")
}

override fun fly() {
println("Bird is flying so high")
}
}

As you can see, in the above example that some animals can’t fly such as cats. So it will be unnecessary to implement the fly method.
To fix that issue, We will create a new Interface for flying animals and will remove the fly method from the animal interface.

interface Animal{
fun eat()
fun sleep()
}

interface FlyingAnimal{
fun fly()
}

class Cat: Animal{
override fun eat() {
println("Cat is eating fish")
}

override fun sleep() {
println("Cat is sleeping on its owner's bed")
}
}

class Bird: Animal, FlyingAnimal{
override fun eat() {
println("Bird is eating forage")
}

override fun sleep() {
println("Bird is sleeping in the nest")
}

override fun fly() {
println("Bird is flying so high")
}
}

5. Dependency Inversion Principle

The Dependency Inversion Principle (DIP) states that high-level modules should not depend upon low-level modules; they should depend on abstractions.

Secondly, abstractions should not depend upon details; details should depend upon abstractions. The idea is that we isolate our class behind a boundary formed by the abstractions it depends on. If all the details behind those abstractions change, then our class is still safe. This helps keep coupling low and makes our design easier to change. DIP also allows us to test things in isolation.

Let’s take an example.

Let’s assume that we need to develop a mobile application for both Android and iOS. To do that, we need an Android Developer and an iOS Developer. These classes will have a method to develop a mobile application by using their own platform and programming language.

class AndroidDeveloper{
fun developMobileApp(){
println("Developing Android Application by using Kotlin")
}
}

class IosDeveloper{
fun developMobileApp(){
println("Developing iOS Application by using Swift")
}
}

fun main(){
val androidDeveloper = AndroidDeveloper()
val iosDeveloper = IosDeveloper()

androidDeveloper.developMobileApp()
iosDeveloper.developMobileApp()
}

To fix the problem here, we can create an interface, and AndroidDeveloper and IosDeveloper classes will implement this interface.

interface MobileDeveloper{
fun developMobileApp()
}

class AndroidDeveloper(var mobileService: MobileServices): MobileDeveloper{
override fun developMobileApp(){
println("Developing Android Application by using Kotlin. " +
"Application will work with ${mobileService.serviceName}")
}
enum class MobileServices(var serviceName: String){
HMS("Huawei Mobile Services"),
GMS("Google Mobile Services"),
BOTH("Huawei Mobile Services and Google Mobile Services")
}
}

class IosDeveloper: MobileDeveloper{
override fun developMobileApp(){
println("Developing iOS Application by using Swift")
}
}

fun main(){
val developers = arrayListOf(AndroidDeveloper(AndroidDeveloper.MobileServices.HMS), IosDeveloper())
developers.forEach { developer ->
developer.developMobileApp()
}
}

SOLID principles are valuable tools in your toolbox, ones you should keep them in back of your mind when designing your next feature or application. That’s it for SOLID principles. It is easy when you understand these principles with simple examples rather than by definition.

--

--