Maison > développement back-end > Tutoriel Python > Décomposer l'inversion de dépendance, l'IoC et la DI

Décomposer l'inversion de dépendance, l'IoC et la DI

DDD
Libérer: 2025-01-20 16:26:09
original
322 Les gens l'ont consulté

Breaking Down Dependency Inversion, IoC, and DI

L'exploration du système d'injection de dépendances de NestJS a déclenché une plongée plus approfondie dans l'inversion de dépendance, l'inversion de contrôle et l'injection de dépendance. Ces concepts, bien qu’apparemment similaires, offrent des solutions distinctes à différents problèmes. Cette explication sert de rappel personnel et, espérons-le, de guide utile pour ceux qui sont aux prises avec ces termes.


  1. Principe d'inversion de dépendance (DIP)

Définition : Les modules de haut niveau ne doivent pas dépendre des modules de bas niveau ; les deux devraient dépendre d’abstractions. Les abstractions ne devraient pas dépendre de détails ; les détails devraient dépendre des abstractions.

Ce que cela signifie :

Dans les logiciels, les modules de haut niveau encapsulent la logique métier de base, tandis que les modules de bas niveau gèrent des implémentations spécifiques (bases de données, API, etc.). Sans DIP, les modules de haut niveau s'appuient directement sur ceux de bas niveau, créant un couplage étroit qui entrave la flexibilité, complique les tests et la maintenance et rend difficile le remplacement ou l'extension des détails de bas niveau.

DIP inverse cette relation. Au lieu d'un contrôle direct, les modules de haut niveau et de bas niveau dépendent d'une abstraction partagée (interface ou classe abstraite).


Sans DIP

Exemple Python

<code class="language-python">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)</code>
Copier après la connexion
Copier après la connexion

Exemple de TypeScript

<code class="language-typescript">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);
    }
}</code>
Copier après la connexion
Copier après la connexion

Problèmes :

  1. Couplage serré : Notification dépend directement de EmailService.
  2. Extensibilité limitée : le passage à SMSService nécessite de modifier Notification.

Avec DIP

Exemple Python

<code class="language-python">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!")</code>
Copier après la connexion
Copier après la connexion

Exemple de TypeScript

<code class="language-typescript">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!");</code>
Copier après la connexion
Copier après la connexion

Avantages du DIP :

  • Flexibilité : échangez facilement les implémentations.
  • Testabilité : utilisez des simulations pour les tests.
  • Maintenabilité : les modifications apportées aux modules de bas niveau n'ont pas d'impact sur ceux de haut niveau.

  1. Inversion de contrôle (IoC)

IoC est un principe de conception selon lequel le contrôle des dépendances est transféré vers un système externe (framework) au lieu d'être géré au sein de la classe. Traditionnellement, une classe crée et gère ses dépendances. IoC inverse cela : une entité externe injecte des dépendances.


Exemple Python : sans IoC

<code class="language-python">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)</code>
Copier après la connexion

Exemple TypeScript : sans IoC

<code class="language-typescript">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);
    }
}</code>
Copier après la connexion

Problèmes sans IoC :

  1. Couplage serré.
  2. Faible flexibilité.
  3. Tests difficiles.

Exemple Python : avec IoC

<code class="language-python">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)</code>
Copier après la connexion
Copier après la connexion

Exemple TypeScript : avec IoC

<code class="language-typescript">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);
    }
}</code>
Copier après la connexion
Copier après la connexion

Avantages de l'IoC :

  1. Couplage lâche.
  2. Changement de mise en œuvre facile.
  3. Testabilité améliorée.

  1. Injection de dépendance (DI)

DI est une technique où un objet reçoit ses dépendances d'une source externe. C'est une implémentation pratique d'IoC, injectant des dépendances via :

  1. Injection de constructeur
  2. Injection de Setter
  3. Injection d'interface

Exemple Python : DI Framework (utilisant la bibliothèque injector)

<code class="language-python">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!")</code>
Copier après la connexion
Copier après la connexion

Exemple TypeScript : DI Framework (utilisant la bibliothèque tsyringe)

<code class="language-typescript">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!");</code>
Copier après la connexion
Copier après la connexion

Avantages de DI :

  • Tests simplifiés.
  • Évolutivité améliorée.
  • Maintenabilité améliorée.

Cette explication détaillée clarifie les relations et les distinctions entre DIP, IoC et DI, en mettant l'accent sur leurs contributions individuelles à la création de logiciels robustes et maintenables.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal