SOLID Principles (Series) [PART 5]
SOLID - make Object-Oriented designs more understandable, flexible and maintainable.
![SOLID Principles (Series) [PART 5]](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1666755370590%2FHkH-Be75-.jpg&w=3840&q=75)
Senior Android Engineer from Bangladesh. Love to contribute in Open-Source. Indie Music Producer.
Search for a command to run...
SOLID - make Object-Oriented designs more understandable, flexible and maintainable.
![SOLID Principles (Series) [PART 5]](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1666755370590%2FHkH-Be75-.jpg&w=3840&q=75)
Senior Android Engineer from Bangladesh. Love to contribute in Open-Source. Indie Music Producer.
Thank you brother.
In this series SOLID Principles with real life example. Happy learning...
SOLID - make Object-Oriented designs more understandable, flexible and maintainable.
A practical guide to choosing the right coroutine primitive for your Android/Kotlin projects

This guide explains what Channels are, when to use them, how to use them correctly, and when NOT to use them β in simple, professional language. 1. What problem do Channels solve? In Kotlin coroutines, you often have multiple coroutines running at t...

Learn how to build preview-safe ViewModels in Jetpack Compose using Hilt.

HandlerInterceptor vs Filter in Spring Boot: A Practical Guide with JNDI Injection Prevention

Simple In-Memory Caching: A Tiny Trick with Massive Impact

If get to know something new by reading my articles, don't forget to endorse me on LinkedIn
Previous articles on SOLID Principles
DIP (Dependency Inversion Principle) states that:
High-levelmodules should not depend onlow-levelmodules. Both should depend onabstractions.
Abstractions should not depend on details. Details should depend on abstractions.Design by contract.
Every dependency in the design should target an interface or an abstract class. No dependency should target a concrete class.
Factories and Abstract Factories can be used as dependency frameworks, but there are specialized frameworks for that such as Spring IOC (Inversion of Control Container).
Let's take an simple Songs Repository example. Where Data Source could be Remote or Local. When device is connected to the internet, data should be fetched from Remote, else it should return whatever has been Cached to the Local.
interface SongsRepository {
fun searchSongs(query : String) : MutableList<SongObject>
}
class SongsRepositoryImpl constructor (private val dataSource : DataSource) : SongsRepository {
@override fun searchSongs(query : String) : MutableList<SongObject> {...}
}
Here, the implementation depends on abstraction (DataSource interface) that can be injected through its constructor.
Let's create the DataSource interface with two implementations of DataSource.
interface DataSource {
fun createConnection(config : DataSourceConfig) : Boolean
fun getConnection() : DataSourceConnection
}
interface RemoteDataSource {
@override fun createConnection(config : DataSourceConfig) : Boolean {...}
@override fun getConnection() : DataSourceConnection {...}
}
interface LocalDataSource {
@override fun createConnection(config : DataSourceConfig) : Boolean {...}
@override fun getConnection() : DataSourceConnection {...}
}
Based on device internet connectivity, we can switch from RemoteDataSource to LocalDataSource (when device is not connected to the internet) then we only need to pass this object from the client.
What's has been done through the example?
SongsRepositoryImpl class depends on the DataSource interface, not the concrete class.
Now due to abstraction, Client can change implementation at any time. For example, when device is connected to the internet, client can pass an instance of RemoteDataSource else LocalDataSource.
High-levelmodules should not depend onlow-levelmodules. Both should depend onabstractions.
Abstractions should not depend on details. Details should depend on abstractions.That's it for this series. Happy Coding...