dimanche 4 mai 2014

Dependency injection into Scala object (singleton)

L'injection de dépendance en Scala est une chose plutôt aisée du fait des possibilités de la syntaxe et des API à disposition. Il existe ainsi plusieurs méthodes permettant de le faire programatiquement, sans fichier de configuration, sans framework comme Spring ou Guice.
Le propos de cet article n'est pas de lister et de comparer toutes les méthodes disponibles pour ce faire; ceci sera traité dans un article ultérieur; mais de décrire une manière d'injecter les dépendances dans un contexte précis.
J'ai récemment eu a participer au développement d'une application web "classique" avec des Dao et des Services.
Ces Dao et Services sont naturellement indiqués pour être utilisés comme des singletons. En Scala, nous disposons d'un mot-clé pour déclarer des singletons : object.
Je vais donc essayer d'illustrer comment injecter une dépendance dans un object Scala et de rendre cet object lui même injectable dans une classe tierce.

Le code

J'utilise un exemple simpliste pour illustrer la méthode d'injection de dépendance. J'ai un objet métier Boat, et je veux créer un repository BoatRepository. J'ai besoin d'injecter dans ce repository une instance de type DB qui me permettra d'utiliser l'api d'un quelconque driver (par exemple un driver mongodb).


L'explication

La méthode est assez simple et le code assez compréhensible par lui-même. Si je résume :
  1. Utiliser une interface abstraite (un trait) pour déclarer les méthodes de mon repository (BoatRepository)
  2. Implémenter ce repository dans un trait en déclarant une dépendance vers une base de type DB (MongoDbBoatDao), cette dépendance étant elle même déclarée dans un trait (Database)
  3. Fournir une implémentation à cette Database (ProdDatabase)
  4. Construire le singleton Dao en mixant les trait MongoDbBoatDao et ProdDatabase
  5. Pour surcharger la dépendance du singleton, par exemple dans un test (MongoDbBoatDaoTest), il suffit de mixer le trait MongoDbBoatDao avec un autre trait surchargeant le membre DB
A noter qu'avec cette manière de faire, le code client n'a pas connaissance des dépendances du DAO, notamment celle vers le driver de base de données, ce qui isole éfficacement les différentes couches entre elles.
A noter aussi que ce système est "scalable", dans le sens ou si je veux injecter le DAO dans un autre singleton, dans un service par exemple, il me suffit de faire la même chose où le DAO prendrait la place de la DB et le service celui du DAO.

Cool non ? :)

ressource

Aucun commentaire:

Enregistrer un commentaire