Dependency Injection

  • Dependency Injection is where a needed dependency is injected by another object.
  • The class being injected has no responsibility in instantiating the object being injected.
  • Some say you avoid declaring objects using ‘new’ - Not 100% correct…
  • Avoid the use of concrete class, where possible

Eg: Database connection.

  • Hardwiring a database connection within a client class.
  • You might be hardcoding the server, username..etc.
  • Not flexible - What if we want want to change database
    • Your client class should no interest in the type of database
    • So the database class should be injected

Without DI:

public class MyService {

    public MySQLDatabase database = new MySQLService("httos://api-test", "[email protected]", "password123");

    public void save(String test){
        database.save(test); 
    }

}

public class Main{

    public void run() {
        MyService myService = new MyService();
        myService.save("test");
    }

}

With DI:

public class MyService {

    private Database database; 

    public MyService(Database database){
        this.database = database;
    }

    public void save(Todo todo){
        database.save(todo);
    }

}

public class Main{

    public void run() {
        Database database = new MySQLService("httos://api-test", "[email protected]", "password123");
        MyService myService = new MyService(database);
        myService.save("test");
    }

}

With DI, we can now switch the database :

  • MyService class didn't know what type of database it was
    • We can switch between MYSQLDatabase or OracleDatabase
class MySQLDatabse implements Database {

    public void save(String test) {}
}

class OracleDatabase implements Database {

    public void save(String test) {}
}
public class Main{

    public void runOracle() {
        Database database = new OracleDatabase("httos://oracle-test", "[email protected]", "qwyer");
        MyService myService = new MyService(database);
        myService.save("test");
    }

    public void runMySQL() {
        Database database = new MySQLService("httos://api-test", "[email protected]", "password123");
        MyService myService = new MyService(database);
        myService.save("test");
    }

}

Applying the Factory Pattern with DI Injection:

public class DatabaseFactory() {

    private String oracleUrl;

    public static Database createOracleDatabase() {
         return new OracleDatabase("httos://oracle-test", "[email protected]", "qwyer");
    }

}

public class Main{

    public void runQuery() {
        Database database = DatabaseFactory.createOracleDatabase(); 
        MyService myService = new MyService(database);
        myService.save("test");
    }

}

Types of DI Injection:

  • By Setters
public class MyService {

    private Database database; 

    public void setDatabase(Database database){
        this.database = database;
    }

}
  • By Constructor (Most preferred)
public class MyService {

    private Database database; 

    public MyService(Database database){
        this.database = database;
    }

}

Concrete Classes vs Interfaces

  • DI can be done with concrete classes (Should be avoided)
  • Prefer interface(Database.class) over concrete classes (MySQLDatabase.class or OracleDatabase.class)
    • Allow runtime to decide the implementation
  • More testable, for unit test (Can create a mock database eg: MockDatabase implements Database)

Inversion of Control (IOC)

  • Technique to allow dependencies to be injected at runtime (Usually done by the framework such as Spring)

From stackoverflow:

"Let's say you have some sort of "repository" class, and that repository is responsible for handing data to you from a data source.

The repository could establish a connection to the data source by itself. But what if it allowed you to pass in a connection to the data source through the repository's constructor?

By allowing the caller to provide the connection, you have decoupled the data source connection dependency from the repository class, allowing any data source to work with the repository, not just the one that the repository specifies.

You have inverted control by handing the responsibility of creating the connection from the repository class to the caller."

IOC vs Dependency Injection

https://stackoverflow.com/questions/6550700/inversion-of-control-vs-dependency-injection

IoC is a generic term meaning rather than having the application, call the methods in a framework, the framework calls implementations provided by the application.

  • Runtime environment of your code (Spring IOC Container), at runtime spring is going to find your classes, perform DI depending how you configured Spring (Such as auto configuration from Spring Boot)

DI is a form of IoC, where implementations are passed into an object through constructors/setters/service lookups, which the object will 'depend' on in order to behave correctly.

  • Compositions of your classes

.

results matching ""

    No results matching ""