Skip to content

Latest commit

 

History

History
380 lines (296 loc) · 10.4 KB

File metadata and controls

380 lines (296 loc) · 10.4 KB

Dependency Inversion Principle (DIP)

// Pending picture

What is DIP?

  1. Never depend on everything concrete(Actual Class), only depend on Abstraction.
  2. High level module should not depend on low level module. They should depend on Abstraction.
  3. Able to change an implementation easily without altering the high level code.
  4. By adhering to DIP, you can create systems that are resilient to change, as modifications to concrete implementations do not affect high-level modules.

In One Statement

The Dependency Inversion Principle suggests that high-level modules should not depend on low-level modules, but both should depend on abstractions. Additionally, abstractions should not depend on details; details should depend on abstractions.

Key Idea

  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.

Interface Segregation Principle

Real-Time Examples

Building a LEGO tower — the bricks (high and low-level modules) connect through smaller bricks (abstractions).

How can Dependency Inversion Principle be applied?

📝 Practical Coding Examples in Java #1

Interface Segregation Principle

Violet DIP

Interface Segregation Principle

// Higher level module: Application
class Application {
    private FileLogger logger;

    public Application(FileLogger logger) {
        this.logger = logger;
    }

    public void process() {
        logger.log("Application started");
        // Additional logic here
    }
}

// Lower level module: FileLogger
class FileLogger {

    public void log(String message) {
        // Code to write the message to a file
    }
}

// New Lower level module: ConsoleLogger
class ConsoleLogger {

    public void log(String message) {
        // Code to write the message to a file
    }
}

public class Example {
    public static void main(String[] args) {
        FileLogger fileLog = new FileLogger();
        ConsoleLogger consoleLog = new ConsoleLogger();
        // We can't pass the consoleLog as params in Application(consoleLog) without modifying the Application, other wise program gives an compile time error.
        Application app = new Application(fileLog);
        app.process();
    }
}

Not Violet DIP

Interface Segregation Principle

// Step 1: Define the Abstraction

// Interface : Ilogger
interface ILogger {
    void log(String message);
}

// Step 2: Implement the Abstraction

// LLM 1: ConsoleLogger
class FileLogger implements ILogger {
    @Override
    public void log(String message) {
        System.out.println("FileLogger: " + message);
    }
}

// LLM 2: ConsoleLogger
class ConsoleLogger implements ILogger {
    @Override
    public void log(String message) {
        System.out.println("ConsoleLogger: " + message);
    }
}

// LLM 3: ExternalServiceLogger
class ExternalServiceLogger implements ILogger {
    @Override
    public void log(String message) {
        System.out.println("ExternalServiceLogger: " + message);
        // Code to send the message to an external service
        // This could involve HTTP requests, dealing with authentication, etc.
    }
}

// Step 3: Higher level app now depends upon Abstraction

// HLM 1: Application
class Application {
    private ILogger logger;

    public Application(ILogger logger) {
        this.logger = logger;
    }

    public void process() {
        logger.log("Application started");
        // Additional logic here
    }
}

public class Example {
    public static void main(String[] args) {
        ILogger fileLog = new FileLogger();
        ILogger consoleLog = new ConsoleLogger();
        ILogger externalServiceLog = new ExternalServiceLogger();

        // Now we dont need to change for passing fileLog, consoleLog, and externalServiceLog as paramas into Application
        Application app1 = new Application(fileLog);
        Application app2 = new Application(consoleLog);
        Application app3 = new Application(externalServiceLog);

        app1.process(); // FileLogger: Application started
        app2.process(); //  ConsoleLogger: Application started
        app3.process(); // ExternalServiceLogger: Application started
    }
}

📝 Practical Coding Examples in Java #2

Interface Segregation Principle

Violet DIP

Interface Segregation Principle

// Higher level module: GoToWork
class GoToWork {
    private Metro metro;
    public GoToWork(Metro metro) {
        this.metro = metro;
    }

    public void process() {
        metro.travel("Transport started");
        // Additional logic here
    }
}

// Lower level module: Metro
class Metro {
    public void travel(String message) {
        // Code to write the message to a file
    }
}

// New Lower level module: Rapido
class Rapido {
    public void travel(String message) {
        // Code to write the message to a file
    }
}

public class Example {
    public static void main(String[] args) {
        Metro metroTransport = new Metro();
        Rapido rapidoTransport = new Rapido();
        // We can't pass the rapidoTransport as params in GoToWork(rapidoTransport) without modifying the GotoWork, other wise program gives an compile time error.
        GoToWork app = new GoToWork(metroTransport);
        app.process();
    }
}

Not Violet DIP

Interface Segregation Principle

// Step 1: Define the Abstraction

// Interface : ITransport
interface ITransport {
    void travel(String message);
}

// Step 2: Implement the Abstraction

// LLM 1: Metro
class Metro implements ITransport {
    @Override
    public void travel(String message) {
        System.out.println("Metro: " + message);
    }
}

// LLM 2: Rapido
class Rapido implements ITransport {
    @Override
    public void travel(String message) {
        System.out.println("Rapido: " + message);
    }
}

// LLM 3: Uber
class Uber implements ITransport {
    @Override
    public void travel(String message) {
        System.out.println("Uber: " + message);
    }
}

// Step 3: Higher level app now depends upon Abstraction

// HLM 1: GoToWork
class GoToWork {
    private ITransport transport;

    public GoToWork(ITransport transport) {
        this.transport = transport;
    }

    public void process() {
        transport.travel("transport started");
        // Additional logic here
    }
}

public class Example {
    public static void main(String[] args) {
        ITransport metroTrav = new Metro();
        ITransport rapidoTrav = new Rapido();
        ITransport uberTrav = new Uber();

        // Now we don't need to change for passing metroTrav, rapidoTrav, and uberTrav as paramas into GoToWork
        GoToWork transport1 = new GoToWork(metroTrav);
        GoToWork transport2 = new GoToWork(rapidoTrav);
        GoToWork transport3 = new GoToWork(uberTrav);


        transport1.process(); // Metro: transport started
        transport2.process(); // Rapido: transport started
        transport3.process(); // Uber: transport started
    }
}

📝 Practical Coding Examples in Java #3

Interface Segregation Principle

package calculatorDIP;

// ICalculator Interface: Abstraction Layer for Both High and Low Level Module
interface ICalculator{
    void operate(int a, int b);
}

// Calculator Class: High Level Module
public class Calculator {
    private ICalculator caloperator;

    public Calculator(ICalculator caloperator){
        this.caloperator = caloperator;
    }

    public void process(int a, int b){
        caloperator.operate(a, b);
    }
}
package calculatorDIP;

// Addition Class: Low Level Module
public class Addition implements ICalculator {
    @Override
    public void operate(int a, int b){
        System.out.println("SUM: "+ (a+b));
    }
}
package calculatorDIP;

// Subtraction Class: Low Level Module
public class Subtraction implements ICalculator {
    @Override
    public void operate(int a, int b){
        System.out.println("SUB: "+ (a-b));
    }
}
package calculatorDIP;

// Multiplication Class: Low Level Module
public class Multiplication implements ICalculator {
    @Override
    public void operate(int a, int b){
        System.out.println("MUL: "+ (a*b));
    }
}
package calculatorDIP;

public class CalMain {
    public static void main(String[] args){
        ICalculator addition = new Addition();
        ICalculator subtraction = new Subtraction();
        ICalculator multiplication = new Multiplication();

        Calculator operate1 = new Calculator(addition);
        Calculator operate2 = new Calculator(subtraction);
        Calculator operate3 = new Calculator(multiplication);

        operate1.process(10, 5);
        operate2.process(20, 10);
        operate3.process(30, 10);
    }
}

📝 Practical Coding Examples in Java #4

Interface Segregation Principle

Try to code the example 4 using the abobe diagram.