Une application est souvent séparée en plusieurs couches, chacune ayant une responsabilité bien définie :
- Présentation
- Accès aux données
- Gestion des règles métiers
- …
Afin d’avoir une application maintenable et testable il est nécessaire d’avoir un faible couplage entre les différentes briques de votre application.
Ce découplage passe par des interfaces qui vont définir le rôle de chaque brique et ce quelles sont capable de faire. Ainsi une brique ne sera pas dépendante d’une implémentation mais d’une interface. Par exemple, la couche présentation est liée via des interfaces à des services. Elle ne sait pas qui implémente ses services. La couche de présentation n’a pas de référence à une implémentation particulière des interfaces des services. On pourra ainsi facilement bouchonner (mock : renvoi de données de test) afin de tester plus facilement son application.
C’est la qu’intervient Unity.
Présentation de Unity
Unity est un conteneur d’injection de dépendances. Il fait partie des patterns & pratices de Microsoft. Unity va vous permettre de définir dans votre application qu’elle est la classe qui implémente une interface et va vous retourner pour vous une instance de cette classe.
La configuration de Unity peut se faire de 2 façons :
- par code (via le méthode RegisterType)
- par fichier xml
Je préconise de passer par un fichier XML qui lui permet de ne pas recompiler l’application.
Voici un exemple de configuration qui permet de définir qu’il faut utiliser la classe MonService lorsque l’on a besoin d’une interface IMonService.
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <containers> <container> <types> <!-- Business services --> <type type="MyInterfaces.IMonService,MyInterfaces" mapTo="MyServices.MonService, MyServices"></type> </types> </container> </containers> </unity>
La résolution par code se fait via la méthode Resolve sur le conteneur :
myContainer.Resolve<MyInterfaces.IMonService>();
Implémentation multiples d’une interface
Dans certains cas, il est possible que vous ayez besoin de plusieurs implémentations d’une même interface. (exemple : communication avec des machines ayant un protocole différents. On va ainsi utiliser le design pattern Commande qui va nous permettre d’avoir une seule interface de communication. Les implémentations permettent de masquer les différences de protocoles).
Il est possible de différentier les implémentations d’une même interface en spécifiant lors de la configuration de Unity un nom via l’attribut name.
Configuration par xml
<type type="MyInterfaces.IMonService, MyInterfaces" mapTo="MyServices.MonService1, MyServices" name="MonInterface1"></type> <type type="MyInterfaces.IMonService, MyInterfaces" mapTo="MyServices.MonService2, MyServices" name="MonInterface2"></type> <type type="MyInterfaces.IMonService, MyInterfaces" mapTo="MyServices.MonService, MyServices" name="MonInterface3"></type>
Configuration par code
myContainer.RegisterType<MyInterfaces.IMonService, MyServices.MonService1>("MonInterface1" ) ;
La résolution se fera via le code suivant :
myContainer.Resolve<MyInterfaces.IMonService>("MonInterface1");
Liens
- Un article concernant l’Architecture en couches, découplage et injection de dépendances avec Unity
- Une liste de conteneurs d’injections de dépendances .NET
- Un article sur l’injection de dépendance dans le magazine MSDN