Inversion de Contrôle (IoC), kesako ?

Concepts

On parle beaucoup de la notion d’Inversion de Contrôle (IoC : Inversion of Control) lors d’utilisation des conteneurs d’injection de dépendances (DI Containers) comme : Spring.Net, Castle Windsor, Unity, etc. Dans la plupart des documents sur ces sujets, on les définit comme des IoC Containers.

Ce billet va tenter de clarifier la notion d’Inversion de Contrôle tel qu’il est défini et dans quelle mesure il est utilisé. Nous ferons aussi un aparté sur une définition plus large de cette notion et comment il est utilisé dans les conteneurs d’injections de dépendances.

Inversion of Control

le principe d’Hollywood : Ne nous appelez pas, c'est nous qui vous appellerons.

L’IoC est un comportement qu’on rencontre souvent dans les frameworks et qui consiste à laisser le contrôle de certains comportements (ex : appel de méthodes spécifiques) au soin du dit framework au lieu de le faire dans le code qu’on a créé. Le cycle de vie d’une page ASP.NET est l’exemple type de ce comportement. ASP.NET passe par une succession d’étapes prédéfinies lors de la construction d’une page suite à une requête. Ces étapes sont les suivantes :

  • `Page request`
  • `Start`
  • `Initialization`
  • `Load`
  • `Validate`
  • `Postback event handling`
  • `Rendering`
  • `Unload`

A chaque étape, il nous est possible d’ajouter un comportement spécifique par l’intermédiaire des événements sur la page à notre disposition. Le déclenchement de ces comportements ne se fait pas dans notre code (on ne les appelle pas explicitement), c’est le serveur web ASP.NET qui s’en chargera. Nous avons fourni (ou enrichi) un comportement, le serveur ou le framework se chargera de l’exécuter selon son pipeline. Nous sommes face à une inversion de contrôle. On retrouve beaucoup cette notion dans les structures à Plugins ou justement, on fourni une implémentation d’un contrat spécifique (celui du plugin), le framework s’occupera de charger et d’exécuter notre implémentation.

Les aficionados du framework ASP.NET MVC l’auraient compris, la notion de filtres fournis avec le framework pratiquent l’inversion de contrôles. On pose l’attribut sur une action par exemple et le tour est joué. Le framework se chargera d’exécuter le code adéquat selon certaines conditions. Toute la magie vient du fait qu’on s’occupe de fournir un comportement, le framework se chargera de son exécution.

Injection de dépendances

Le but en utilisant l’injection de dépendances est de s’abstraire de toute la logique de construction, de gestion du cycle de vie des objets tiers dont mon programme (mon objet métier) a besoin. Si on prend l’analogie d’un artisan peintre, son savoir-faire est de faire de la peinture. Pour se faire, il a besoin de peintures, rouleaux, escabot, etc. Tous ces prérequis lui sera fourni au moment ou il en aura besoin et il n’a pas besoin de savoir d’ou ça vient, comment et/ou combien ça a été acheté.

En ce sens, l’injection de dépendance se rapproche plus du principe de la Séparation des Préoccupations (SoC : Separation of Concern. Mon objet se concentre sur ce qu’il doit faire et toutes les dépendances dont il a besoin sera fourni par le container au moment ou il en aura besoin. Mon objet n’aura pas à gérer ni la création ni la destruction de ces dépendances.

De par ce principe, on a introduit un couplage faible entre mon objet et ses dépendances. Vous trouverez ici une explication plus poussée de l’utilisation du container Spring.NET pour faire de l’injection de dépendances.

Inversion de Contrôle par Injection de Dépendances

Dans une assertion plus large, on peut effectivement considérer les conteneurs d’injection de dépendances comme faisant de l’Inversion de Contrôle dans le sens ou la gestion des cycles de vie des objets n’est pas gérée par nous même (notre code métier) mais laissée au conteneur. Si on tire le raisonnement plus loin, le design pattern Factory rentre aussi dans cette catégorie car dans une moindre mesure, elle gère le cycle de vie des objets qu’on lui demande à notre place. Mais comme nous venons de voir, l’inversion de contrôle est une notion beaucoup plus large et plus globale.