Solid Principles
In this tutorial we are going to learn about the Dependency Inversion Principle (DIP).
Reference
Dependency Inversion Principle (DIP) states that high level classes must not depend on low level classes. Both must depend on abstractions.
The objective of this principle is to decouple the classes.
These are the classes that implements low level operations like access files, interacting with database, making network call, etc.
These are the classes that contains some sort of business logic and uses the low level classes to carry out their tasks.
In the following Java program we have the MySQL class which is the low-level class and it is used by the User class which is the high-level class.
class MySQL {
public String connection() {
return "Connection successful.";
}
public String insert() {
return "Row inserted!";
}
}
class PostgreSQL {
public String dbCon() {
return "Connected to database on port 5432";
}
public String create() {
return "New row created!";
}
}
class User {
private final MySQL mySQL;
public User(MySQL mySQL) {
this.mySQL = mySQL;
}
public String createUser() {
// do something...
return mySQL.insert();
}
}
Test
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class DIPTests {
@Test
@DisplayName("Using MySQL")
public void shouldUseConcreteClass() {
MySQL mySQL = new MySQL();
User user = new User(mySQL);
Assertions.assertEquals(user.createUser(), "Row inserted!");
}
}
The high-level class User is directly dependent on the low-level class MySQL. If we want to change the database from MySQL to PostgreSQL then we would have to make changes in the User class which would clearly violet the Open-Closed Principle.
To solve this problem we would have to make the high-level class User depend on an abstraction. For this we are going to create the Database interface which is implemented by the MySQL and PostgreSQL database.
interface Database {
public String connect();
public String insert();
}
class MySQL implements Database {
@Override
public String connect() {
return "Connected on port 3306.";
}
@Override
public String insert() {
return "Inserted 1 row.";
}
}
class PostgreSQL implements Database {
@Override
public String connect() {
return "Connected on port 5432.";
}
@Override
public String insert() {
return "Inserted 1 row.";
}
}
class User {
private final Database database;
public User(Database database) {
this.database = database;
}
public String create() {
return database.insert();
}
}
Test
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class DIPTests {
@Test
@DisplayName("Using abstraction")
public void shouldUseAbstraction() {
Database database = new MySQL();
User user = new User(database);
Assertions.assertEquals(user.create(), "Inserted 1 row.");
}
}
ADVERTISEMENT