Injection de Dépendances et Inversion de Controle

Injection de Dépendances

L'injection de dépendances (dependency injection en anglais) est un mécanisme qui permet d'implémenter le principe de l'inversion de contrôle.

Le principe est que le flot d'exécution d'un logiciel n'est plus sous le contrôle direct de l'application elle-même mais du framework ou de la couche logicielle sous-jacente.

Permet de définir les objets nécessaires au fonctionnement d’un objet non pas de façon statique ( explicitement dans le code) mais dynamique (lors de son exécution). Permet de limiter les adhérences entre les différente couches.

interface IemailSender

{ void Send(string to, string subject, string message);}

class EmailSender : IemailSender

{

public void Send(string to, string subject, string message)

{ // Send the email…}

}

class Controller

{

private IEmailSender _emailSender;


public Controller(IEmailSender emailSender)

{

_emailSender = emailSender;

}

public void DoStuff()

{

_emailSender.Send("j@j.com", "Email Subject", "This is the content !");

}

}

Cela permet de modifier le comportement d’un objet très simplement dans le cadre de test unitaire, de changement d’un librairie, etc …

Dans notre cas Unity ou Structure Map.

Les types d’injection de dépendance possibles :
  • Injection par une propriété (par modificateur)
  • Injection par le constructeur

Inversion de contrôle (IOC)

 Principe de l'IOC

L'idée est la suivante: au lieu d'invoquer le constructeur d'une classe pour initialiser les objets dont nous avons besoin dans le corps d'une méthode, nous utilisons souvent des Fabriques, parfois Abstraites. Cette pratique limite le couplage entre les classes, mais le passage obligé par la Fabrique introduit une certaine lourdeur syntaxique. L'IOC propose simplement de définir comme propriétés de la classe utilisatrice tous les objets dont elle aura besoin. Afin de limiter le couplage, on sera bien avisé de choisir des interfaces ou des classes abstraites comme types apparents de ces propriétés. Une fois que tout est déclaré, les méthodes de la classe utilisatrice peuvent considérer que les propriétés seront correctement initialisées, comme par magie. Cette magie est implémentée par le Conteneur IOC, qui se base sur un ou plusieurs fichiers de paramétrage XML pour savoir quand et comment initialiser les propriétés de toutes les classes utilisatrices de l'application. Ainsi, la complexité d'initialisation n'est plus située dans la classe utilisatrice (comme avec l'invocation directe du constructeur), ni dans une fabrique abstraite invoquée par cette même classe, mais dans un fichier de configuration complètement externe à cette classe. Le framework d'IOC dépend bel et bien de toutes les classes (utilisatrices et implémentatrices de services) mais les classes, elles, ne dépendent plus que d'interfaces. Nous avons inversé la dépendance, ou inversé le contrôle, d'où le nom de ce mécanisme. 

Effectivement, disposer d'un conteneur IOC pour résoudre les dépendances entre classes, en particulier entre classes de niveaux d'abstraction différents, s'avère très pratique. Le code se simplifie mais le prix à payer est bien sûr de déplacer cette complexité dans les fichiers de configuration du framework.

Maintenant que nous avons une meilleure idée du mécanisme d'IOC, essayons d'en évaluer les problèmes résiduels:


• Redondance: les attributs positionnés par le framework (ou les accesseurs aux attributs), qui ont pourtant été déclarés dans le code des classes, doivent être mentionnés à nouveau dans les fichiers de configuration du framework. Cette redondance augmente le coût du développement et de la maintenance évolutive et ne favorise pas l'agilité dudit développement.

• Robustesse: les frameworks d'IOC fonctionnent à l'exécution; il faut donc lancer l'application pour en tester la robustesse, et il vaut mieux disposer de tests unitaires assez agressifs pour s'assurer qu'il n'existe aucune erreur de saisie entre le code de l'application et le paramétrage du framework. Aucune vérification de ce type n'est possible au moment de la compilation, ce qui peut s'avérer pénalisant.

En complément de ces nouveaux outils, il faudra donc disposer de logiciels statiques qui permettront de vérifier automatiquement l'adéquation entre code et paramétrage. Mieux, il faudrait qu'à partir du code, on puisse générer automatiquement les documents de paramétrage "type", quitte à devoir les retoucher par la suite (dans le cas contraire, la saisie et la maintenance de ces fichiers sera certainement fastidieuse).

Commentaires

Posts les plus consultés de ce blog

Sécurité des Applications

Principes de la Programmation Orientée Objet

Principe de Responsabilité Unique