SOLID Principles: Dependency Inversion Principle (DIP)

amburi

Amburi Roy

Posted on September 11, 2023

SOLID Principles: Dependency Inversion Principle (DIP)

🪨 SOLID Principles

SOLID is a list of 5 software engineering principles. It is a meta acronym where each letter corresponds to another acronym:

Without any further ado, let's jump into today's topic:

Dependency Inversion Principle (DIP)

Dependency Inversion Principle (DIP) is one of the SOLID principles of object-oriented programming.

It suggests two main principles:

  • High-level modules should not depend on low-level modules, but both should depend on abstractions (the Inversion of Control)
  • Abstractions should not depend on details, but details should depend on abstractions.

Goal: The primary goal of the Dependency Inversion Principle is to reduce the coupling between software modules by promoting a flexible and maintainable architecture. It encourages the use of abstractions and interfaces to decouple high-level modules from low-level implementations.

Advantages:

  1. Reduced Coupling: DIP leads to reduced coupling between different modules or classes in a software system. This makes the codebase more flexible and less prone to ripple effects when changes are made.

  2. Improved Testability: Code that adheres to DIP is easier to test. High-level modules can be tested in isolation using mock objects or test doubles, allowing for more effective unit testing.

  3. Increased Reusability: Abstractions and interfaces foster code reusability. High-level modules can work with different low-level implementations as long as they adhere to the same abstractions.

  4. Ease of Maintenance: DIP makes it easier to maintain the software system because changes to one module are less likely to affect other modules. It promotes a modular and loosely coupled design.

Bad Example:

class PaymentProcessor {
    public function processPayment($amount, $gateway) {
        if ($gateway === 'Google') {
            // Code to process payment with Google gateway
        } elseif ($gateway === 'Apple') {
            // Code to process payment with Apple gateway
        }
    }
}

$paymentProcessor = new PaymentProcessor();
$paymentProcessor->processPayment(100, 'Google');
Enter fullscreen mode Exit fullscreen mode

Here, the PaymentProcessor class directly depends on the specific payment gateway implementations ('Google' and 'Apple'). This high-level module is tightly coupled to low-level details, violating the Dependency Inversion Principle.

Good Example:

interface PaymentGateway {
    public function processPayment($amount);
}

class GooglePaymentGateway implements PaymentGateway {
    public function processPayment($amount) {
        // Code to process payment with Google gateway
    }
}

class ApplePaymentGateway implements PaymentGateway {
    public function processPayment($amount) {
        // Code to process payment with Apple gateway
    }
}

class PaymentProcessor {
    private $gateway;

    public function __construct(PaymentGateway $gateway) {
        $this->gateway = $gateway;
    }

    public function processPayment($amount) {
        $this->gateway->processPayment($amount);
    }
}

$googleGateway = new GooglePaymentGateway();
$paymentProcessor = new PaymentProcessor($googleGateway);
$paymentProcessor->processPayment(100);
Enter fullscreen mode Exit fullscreen mode

Here, we have adhered to the Dependency Inversion Principle by introducing the PaymentGateway interface. The PaymentProcessor class depends on the abstract PaymentGateway interface rather than concrete implementations. This decoupling allows for flexibility and ease of maintenance. Different payment gateways can be added without modifying existing code, making the system more extensible and adhering to DIP principles.

💖 💪 🙅 🚩
amburi
Amburi Roy

Posted on September 11, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related