Tout savoir et plus sur le pattern IAdaptable du framework Eclipse

Dans cet article je vais essayer d'expliquer à quoi sert et comment fonctionne le pattern IAdaptable d'Eclipse. Pour aller plus loin dans sa compréhension, il m'a également paru opportun de décrire plus en profondeur le principe du design pattern Adapter et de ses accolytes (design patterns structuraux) : Proxy, Facade, Bridge et Decorator. Je ne vais pas ici faire un cours complet sur ces pattern mais simplement les présenter et montrer par quelles analogies/distinctions subtiles on peut les rapprocher.

Pour ceux qui sont pressés de comprendre l'implémentation codée, j'ai choisi de la présenter en premier (je fais partie des gens qui préfèrent lire un code avant de se perdre dans la théorie !). Voici donc le plan de cet article :

  1. IAdaptable : une implémentation du design pattern Adapter
  2. Intérets et rôles
  3. Lien avec le design pattern Bridge
  4. Lien avec les design pattern Decorator, Proxy et Façade
  5. Sources

IAdaptable : une implémentation du design pattern Adapter

Qu'est-ce que le pattern IAdaptable et quel est son but ? Une première réponse conscise à cette question, avant de le présenter plus en détail dans la suite de cet article, consiste à dire que IAdaptable est l'implémentation, dans le framework Eclipse, du design pattern Adapter. Son rôle est de permettre à une application d'utiliser de manière transparente des objets dont les interfaces ne sont à priori pas compatibles.

L'adapter va donc d'une part implémenter l'interface de l'objet désiré (afin de répondre au contrat attendu) et d'autre part instancier l'objet qui doit être adapté. Une explication concrète est donnée dans la source (2) avec l'exemple d'une clef a cliquet (soyons pragmatiques !). Les sources (1) et (3) quant à elles fournissent plusieurs extraits de code illustrant la mise en place d'un adapter dans plusieurs contextes.

Intérêts et rôles

Le principal intérêt de ce pattern est de permettre la réutilisabilité d'un code hérité : pendant un développement, il peut s'avérer indispensable de récupérer des objets existants, mais leur comportement ne colle pas toujours avec ce qui est nouvellement mis en place. La création d'adapteurs comble donc le manque d'interfaces compatibles, sans avoir à modifier le code existant : c'est cette nouvelle couche d'abstraction qui liera les deux systèmes.

Un autre aspect important est qu'il permet de structurer les relations entre classes en respectant la loi de Déméter : grâce à l'interface qu'il fournit au client, un objet qui implémente Adapter autorise l'accès à ses propriétés internes sans pour autant créer de couplage fort avec le client.

Lien avec le design pattern Bridge

Maintenant que nous connaissons mieux le pattern Adapter, nous allons voir en quoi il ressemble et est à la fois très différent du pattern Bridge.

Le principe de ce dernier est de découpler l'interface de l'implémentation, afin que chacune puisse évoluer indépendamment. Mais contrairement à Adapter, cette organisation est mise en place avant le développement, pour architecturer les objets et leurs comportements et non pas les adapter les uns aux autres. Pour faire simple, alors que Adapter est parfois plus connu sous le nom de Wrapper, Bridge est quant à lui plutôt nommé Driver. La source (4) expose ces relations et fournit des liens vers Bridge pour comprendre tous les mécanismes.

Lien avec les design pattern Decorator, Proxy et Façade

L'idée propagée par Decorator est de pouvoir attacher dynamiquement de nouvelles responsabilités à un objet : son interface initiale n'est jamais modifiée, mais de nouveaux services lui sont rendus disponibles. Il est donc une alternative simple à l'héritage. On voit donc la différence avec Decorator qui enveloppe l'objet pour lui fournir une nouvelle interface.

Proxy quant à lui a pour but de fournir une couche intermédiaire de manipulation entre le client et l'objet mais en reprenant la même interface que celle de l'objet. Il permet donc de rajouter quelques fonctionnalités lors des accès comme des contrôles de sécurité ou de "lazy instantiation".

Enfin, le pattern Facade peut être vu comme une extension de Adapter, puisqu'il permet l'accès et la manipulation de plusieurs objets avec un seul point d'entrée commun.

[Edit]

Comme il m'a été suggéré plusieurs fois ces derniers jours, je rajoute à mon article une présentation de l'AdapterFactory disponible dans le framework Eclipse.

Comme je l'ai décrit plus haut, un Adapter utilise d'un côté l'interface attendue par le client et implémente d'un autre côté l'objet adapté. On voit donc qu'il existe un couplage "fort" entre ces trois entités.

Pour pallier à ce problème, la plateforme Eclipse RCP fourni un système d'AdapterFactory qui consiste en la chose suivante : des fichiers de configuration permettent de déclarer d'une part la factory elle-même et d'autre part les objets dont elle sera responsable. Ainsi, elle pourra être interrogée comme un service par le client : "je dispose de cet objet, fourni moi l'adapter dont j'ai besoin par rapport à l'interface que j'utilise".

Cette configuration est détaillée dans les sources (3), (9) et (10) que je vous laisse découvrir pour ne pas les plagier. L'intérêt principal de ce système est de laisser intacts les objets métiers, sans même devoir leur faire implémenter IAdaptable, au profit d'une gestion de plus au niveau, au runtime du framework.

Sources

  1. http://userpages.umbc.edu/~tarr/dp/lectures/Adapter-2pp.pdf
  2. http://sourcemaking.com/design_patterns/adapter
  3. http://www.eclipse.org/resources/resource.php?id=407
  4. http://www.c2.com/cgi/wiki?AdapterPattern
  5. http://www.c2.com/cgi/wiki?HandleBodyPattern
  6. http://www.vogella.de/articles/DesignPatternAdapter/article.html
  7. http://fishbolt.org/java/org.fishbolt.common/doc/article.en.html
  8. http://www.mcdonaldland.info/2007/11/28/40/
  9. http://wiki.eclipse.org/FAQ_How_do_I_use_IAdaptable_and_IAdapterFactory%3F
  10. http://www.eclipse.org/articles/article.php?file=Article-Adapters/index.html

Fichier(s) joint(s) :

5 commentaires: