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.
If get to know something new by reading my articles, don't forget to endorse me on LinkedIn
Previous articles on SOLID Principles
What is DIP?
DIP (Dependency Inversion Principle) states that:
High-levelmodules should not depend onlow-levelmodules. Both should depend onabstractions.
Abstractionsshould not depend on details. Details should depend onabstractions.
Things to remember
Design by
contract.Every
dependencyin the design should target aninterfaceor anabstractclass. Nodependencyshould target a concrete class.FactoriesandAbstract Factoriescan be used as dependency frameworks, but there are specialized frameworks for that such asSpring 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.
Example
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?
SongsRepositoryImplclass depends on theDataSourceinterface, not the concrete class.Now due to
abstraction,Clientcan changeimplementationat any time. For example, when device is connected to the internet, client can pass aninstanceofRemoteDataSourceelseLocalDataSource.
Recap
High-levelmodules should not depend onlow-levelmodules. Both should depend onabstractions.
Abstractionsshould not depend on details. Details should depend onabstractions.
That's it for this series. Happy Coding...




