SOLID Principles (Series) [PART 5]
SOLID - make Object-Oriented designs more understandable, flexible and maintainable.
Table of contents
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-level
modules should not depend onlow-level
modules. Both should depend onabstractions
.
Abstractions
should not depend on details. Details should depend onabstractions
.
Things to remember
Design by
contract
.Every
dependency
in the design should target aninterface
or anabstract
class. Nodependency
should target a concrete class.Factories
andAbstract Factories
can 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?
SongsRepositoryImpl
class depends on theDataSource
interface, not the concrete class.Now due to
abstraction
,Client
can changeimplementation
at any time. For example, when device is connected to the internet, client can pass aninstance
ofRemoteDataSource
elseLocalDataSource
.
Recap
High-level
modules should not depend onlow-level
modules. Both should depend onabstractions
.
Abstractions
should not depend on details. Details should depend onabstractions
.
That's it for this series. Happy Coding...