Table of Contents
Dependency Inversion Principle (DIP)
What This Means:
Without DIP
Python Example
TypeScript Example
With DIP
Benefits of DIP:
Inversion of Control (IoC)
Python Example: Without IoC
TypeScript Example: Without IoC
Python Example: With IoC
TypeScript Example: With IoC
Benefits of IoC:
Dependency Injection (DI)
Python Example: DI Framework (using injector library)
TypeScript Example: DI Framework (using tsyringe library)
Benefits of DI:
Home Backend Development Python Tutorial Breaking Down Dependency Inversion, IoC, and DI

Breaking Down Dependency Inversion, IoC, and DI

Jan 20, 2025 pm 04:26 PM

Breaking Down Dependency Inversion, IoC, and DI

Exploring NestJS's dependency injection system sparked a deeper dive into Dependency Inversion, Inversion of Control, and Dependency Injection. These concepts, while seemingly similar, offer distinct solutions to different problems. This explanation serves as a personal refresher, and hopefully, a helpful guide for others grappling with these terms.


  1. Dependency Inversion Principle (DIP)

Definition: High-level modules shouldn't depend on low-level modules; both should depend on abstractions. Abstractions shouldn't depend on details; details should depend on abstractions.

What This Means:

In software, high-level modules encapsulate core business logic, while low-level modules handle specific implementations (databases, APIs, etc.). Without DIP, high-level modules directly rely on low-level ones, creating tight coupling that hinders flexibility, complicates testing and maintenance, and makes replacing or extending low-level details difficult.

DIP reverses this relationship. Instead of direct control, both high-level and low-level modules depend on a shared abstraction (interface or abstract class).


Without DIP

Python Example

class EmailService:
    def send_email(self, message):
        print(f"Sending email: {message}")

class Notification:
    def __init__(self):
        self.email_service = EmailService()

    def notify(self, message):
        self.email_service.send_email(message)
Copy after login
Copy after login

TypeScript Example

class EmailService {
    sendEmail(message: string): void {
        console.log(`Sending email: ${message}`);
    }
}

class Notification {
    private emailService: EmailService;

    constructor() {
        this.emailService = new EmailService();
    }

    notify(message: string): void {
        this.emailService.sendEmail(message);
    }
}
Copy after login
Copy after login

Problems:

  1. Tight coupling: Notification directly depends on EmailService.
  2. Limited extensibility: Switching to SMSService requires modifying Notification.

With DIP

Python Example

from abc import ABC, abstractmethod

class MessageService(ABC):
    @abstractmethod
    def send_message(self, message):
        pass

class EmailService(MessageService):
    def send_message(self, message):
        print(f"Sending email: {message}")

class Notification:
    def __init__(self, message_service: MessageService):
        self.message_service = message_service

    def notify(self, message):
        self.message_service.send_message(message)

# Usage
email_service = EmailService()
notification = Notification(email_service)
notification.notify("Hello, Dependency Inversion!")
Copy after login
Copy after login

TypeScript Example

interface MessageService {
    sendMessage(message: string): void;
}

class EmailService implements MessageService {
    sendMessage(message: string): void {
        console.log(`Sending email: ${message}`);
    }
}

class Notification {
    private messageService: MessageService;

    constructor(messageService: MessageService) {
        this.messageService = messageService;
    }

    notify(message: string): void {
        this.messageService.sendMessage(message);
    }
}

// Usage
const emailService = new EmailService();
const notification = new Notification(emailService);
notification.notify("Hello, Dependency Inversion!");
Copy after login
Copy after login

Benefits of DIP:

  • Flexibility: Easily swap implementations.
  • Testability: Use mocks for testing.
  • Maintainability: Changes in low-level modules don't impact high-level ones.

  1. Inversion of Control (IoC)

IoC is a design principle where dependency control shifts to an external system (framework) instead of being managed within the class. Traditionally, a class creates and manages its dependencies. IoC reverses this—an external entity injects dependencies.


Python Example: Without IoC

class SMSService:
    def send_message(self, message):
        print(f"Sending SMS: {message}")

class Notification:
    def __init__(self):
        self.sms_service = SMSService()  # Dependency created internally

    def notify(self, message):
        self.sms_service.send_message(message)
Copy after login

TypeScript Example: Without IoC

class SMSService {
    sendMessage(message: string): void {
        console.log(`Sending SMS: ${message}`);
    }
}

class Notification {
    private smsService: SMSService;

    constructor() {
        this.smsService = new SMSService(); // Dependency created internally
    }

    notify(message: string): void {
        this.smsService.sendMessage(message);
    }
}
Copy after login

Problems Without IoC:

  1. Tight coupling.
  2. Low flexibility.
  3. Difficult testing.

Python Example: With IoC

class EmailService:
    def send_email(self, message):
        print(f"Sending email: {message}")

class Notification:
    def __init__(self):
        self.email_service = EmailService()

    def notify(self, message):
        self.email_service.send_email(message)
Copy after login
Copy after login

TypeScript Example: With IoC

class EmailService {
    sendEmail(message: string): void {
        console.log(`Sending email: ${message}`);
    }
}

class Notification {
    private emailService: EmailService;

    constructor() {
        this.emailService = new EmailService();
    }

    notify(message: string): void {
        this.emailService.sendEmail(message);
    }
}
Copy after login
Copy after login

Benefits of IoC:

  1. Loose coupling.
  2. Easy implementation switching.
  3. Improved testability.

  1. Dependency Injection (DI)

DI is a technique where an object receives its dependencies from an external source. It's a practical implementation of IoC, injecting dependencies via:

  1. Constructor Injection
  2. Setter Injection
  3. Interface Injection

Python Example: DI Framework (using injector library)

from abc import ABC, abstractmethod

class MessageService(ABC):
    @abstractmethod
    def send_message(self, message):
        pass

class EmailService(MessageService):
    def send_message(self, message):
        print(f"Sending email: {message}")

class Notification:
    def __init__(self, message_service: MessageService):
        self.message_service = message_service

    def notify(self, message):
        self.message_service.send_message(message)

# Usage
email_service = EmailService()
notification = Notification(email_service)
notification.notify("Hello, Dependency Inversion!")
Copy after login
Copy after login

TypeScript Example: DI Framework (using tsyringe library)

interface MessageService {
    sendMessage(message: string): void;
}

class EmailService implements MessageService {
    sendMessage(message: string): void {
        console.log(`Sending email: ${message}`);
    }
}

class Notification {
    private messageService: MessageService;

    constructor(messageService: MessageService) {
        this.messageService = messageService;
    }

    notify(message: string): void {
        this.messageService.sendMessage(message);
    }
}

// Usage
const emailService = new EmailService();
const notification = new Notification(emailService);
notification.notify("Hello, Dependency Inversion!");
Copy after login
Copy after login

Benefits of DI:

  • Simplified testing.
  • Improved scalability.
  • Enhanced maintainability.

This detailed explanation clarifies the relationships and distinctions between DIP, IoC, and DI, emphasizing their individual contributions to building robust and maintainable software.

The above is the detailed content of Breaking Down Dependency Inversion, IoC, and DI. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to solve the permissions problem encountered when viewing Python version in Linux terminal? How to solve the permissions problem encountered when viewing Python version in Linux terminal? Apr 01, 2025 pm 05:09 PM

Solution to permission issues when viewing Python version in Linux terminal When you try to view Python version in Linux terminal, enter python...

How to avoid being detected by the browser when using Fiddler Everywhere for man-in-the-middle reading? How to avoid being detected by the browser when using Fiddler Everywhere for man-in-the-middle reading? Apr 02, 2025 am 07:15 AM

How to avoid being detected when using FiddlerEverywhere for man-in-the-middle readings When you use FiddlerEverywhere...

How to efficiently copy the entire column of one DataFrame into another DataFrame with different structures in Python? How to efficiently copy the entire column of one DataFrame into another DataFrame with different structures in Python? Apr 01, 2025 pm 11:15 PM

When using Python's pandas library, how to copy whole columns between two DataFrames with different structures is a common problem. Suppose we have two Dats...

How to teach computer novice programming basics in project and problem-driven methods within 10 hours? How to teach computer novice programming basics in project and problem-driven methods within 10 hours? Apr 02, 2025 am 07:18 AM

How to teach computer novice programming basics within 10 hours? If you only have 10 hours to teach computer novice some programming knowledge, what would you choose to teach...

How does Uvicorn continuously listen for HTTP requests without serving_forever()? How does Uvicorn continuously listen for HTTP requests without serving_forever()? Apr 01, 2025 pm 10:51 PM

How does Uvicorn continuously listen for HTTP requests? Uvicorn is a lightweight web server based on ASGI. One of its core functions is to listen for HTTP requests and proceed...

How to solve permission issues when using python --version command in Linux terminal? How to solve permission issues when using python --version command in Linux terminal? Apr 02, 2025 am 06:36 AM

Using python in Linux terminal...

How to get news data bypassing Investing.com's anti-crawler mechanism? How to get news data bypassing Investing.com's anti-crawler mechanism? Apr 02, 2025 am 07:03 AM

Understanding the anti-crawling strategy of Investing.com Many people often try to crawl news data from Investing.com (https://cn.investing.com/news/latest-news)...

See all articles