0
0
LldConceptBeginner · 3 min read

Dependency Inversion Principle: Definition and Examples

The Dependency Inversion Principle is a design guideline that says high-level modules should not depend on low-level modules; both should depend on abstractions like interfaces or abstract classes. It helps make code flexible and easier to change by reducing direct dependencies between parts.
⚙️

How It Works

Imagine you have a TV remote (high-level module) and a TV (low-level module). Instead of the remote knowing exactly how the TV works inside, it talks through a common interface like buttons and signals. This way, you can swap the TV with another brand without changing the remote.

The Dependency Inversion Principle works the same way in software. Instead of a high-level part of your program depending directly on a low-level part, both depend on an abstract layer. This abstraction hides details and allows parts to change independently.

This reduces tight coupling, which means changes in one part don’t break others. It also makes testing easier because you can replace real parts with simple mock versions.

💻

Example

This example shows a simple way to apply the Dependency Inversion Principle using interfaces in Python.

python
from abc import ABC, abstractmethod

class Switchable(ABC):
    @abstractmethod
    def turn_on(self):
        pass

    @abstractmethod
    def turn_off(self):
        pass

class LightBulb(Switchable):
    def turn_on(self):
        print("LightBulb: turned on")

    def turn_off(self):
        print("LightBulb: turned off")

class Switch:
    def __init__(self, device: Switchable):
        self.device = device

    def operate(self, on: bool):
        if on:
            self.device.turn_on()
        else:
            self.device.turn_off()

# Usage
light = LightBulb()
switch = Switch(light)
switch.operate(True)
switch.operate(False)
Output
LightBulb: turned on LightBulb: turned off
🎯

When to Use

Use the Dependency Inversion Principle when you want to make your code easier to maintain and extend. It is especially helpful in large projects where many parts interact.

For example, in a payment system, instead of hardcoding a specific payment gateway, you define an interface for payment processing. This lets you add new gateways without changing the main code.

It also helps when writing tests, because you can replace real parts with simple mock objects that follow the same interface.

Key Points

  • High-level modules should not depend on low-level modules directly.
  • Both should depend on abstractions like interfaces or abstract classes.
  • Abstractions should not depend on details; details depend on abstractions.
  • Reduces tight coupling and improves flexibility.
  • Makes testing and maintenance easier.

Key Takeaways

Depend on abstractions, not on concrete implementations.
Use interfaces or abstract classes to decouple high-level and low-level modules.
This principle improves code flexibility and testability.
It helps avoid tight coupling and makes future changes easier.
Apply it especially in large or complex systems with many interacting parts.