Sobes.tech
Middle

What is the D letter in the SOLID principles?

sobes.tech AI

Answer from AI

Dependency Inversion Principle (DIP). It states that:

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
  2. Abstractions should not depend on details. Details should depend on abstractions.

This principle aims to reduce coupling between system components, making them more flexible and easier to test. Instead of direct dependence on specific implementations, components depend on interfaces or abstract classes.

Example without DIP:

// Low-level module
class Database {
    public void save(String data) {
        System.out.println("Saving data to database: " + data);
    }
}

// High-level module depending on low-level
class DataProcessor {
    private Database db = new Database(); // Direct dependency

    public void processAndSave(String data) {
        // Processing logic
        db.save(data);
    }
}

Example with DIP:

// Abstraction (interface)
interface DataSaver {
    void save(String data);
}

// Low-level module depending on abstraction
class Database implements DataSaver {
    @Override
    public void save(String data) {
        System.out.println("Saving data to database: " + data);
    }
}

// Another possible low-level implementation
class FileSaver implements DataSaver {
    @Override
    public void save(String data) {
        System.out.println("Saving data to file: " + data);
    }
}

// High-level module depending on abstraction
class DataProcessor {
    private final DataSaver dataSaver; // Dependency on abstraction

    // Dependency injection via constructor
    public DataProcessor(DataSaver dataSaver) {
        this.dataSaver = dataSaver;
    }

    public void processAndSave(String data) {
        // Processing logic
        dataSaver.save(data); // Using abstraction
    }
}

// Usage
class Main {
    public static void main(String[] args) {
        // High-level module does not depend on specific implementations of Database or FileSaver
        // It depends on the DataSaver abstraction
        DataSaver databaseSaver = new Database();
        DataProcessor processor1 = new DataProcessor(databaseSaver);
        processor1.processAndSave("Some important data");

        DataSaver fileSaver = new FileSaver();
        DataProcessor processor2 = new DataProcessor(fileSaver);
        processor2.processAndSave("Another piece of data");
    }
}

In the DIP example, DataProcessor (high-level module) depends on the DataSaver interface (abstraction), not on the concrete Database (low-level module). Database and FileSaver (details) depend on the same abstraction DataSaver. This allows easy swapping of low-level implementations without changing high-level modules.