3. TP de C++ n°3 Le pattern Adapter

3.1. Etude du pattern Adapter

Le but du pattern Adapter est de permettre d'utiliser une classe dont vous n'avez pas le source dans vos hiérarchies. En outre, il permet également, et c'est un bon comportement d'intégrer des classes dont vous avez le source mais que vous ne voulez pas modifier.

Soit une classe A à intégrer dans la hiérarchie suivante :

Figure 3.1 La hiérarchie dans laquelle il faut intégrer une classe A

La classe E, adaptée de A vers la hiérarchie BCD doit, de toute évidence dériver de B. Toutefois, pour utiliser les méthodes de A, il y a deux solutions :

Etudions les conséquences des deux modèles

3.1.1 Adaptation par héritage multiple

Ce pattern correspond au schéma suivant :

Figure 3.2 le pattern Adapter par héritage

Tout d'abord, il est impossible d'utiliser cette forme du pattern Adapter dans les langages qui bannissent l'héritage multiple.

Cette solution présente toutefois tous les avantages liés à l'héritage. D'une part elle est très simple à mettre en oeuvre car ne nécessite pas d'objet externe. En effet, E héritant directement de A, il peut utiliser son constructeur sans complexe. En outre, et toujours du fait de l'héritage, E peut utiliser les membres protégés de A en plus de ses membres publics, ce qui se révèlera impossible dans la version avec la solution par agrégation.

Il y a toutefois une grave limitation à l'utilisation d'Adapter par héritage. Supposons désormais que A possède au moins une classe fille A'. Si vous voulez adapter à la fois A et A', il faudra utiliser 2 classes différentes E et E'. Nous allons voir que cette limitation n'existe pas avec la version par agrégation.

3.1.2 Adaptation par agrégation

Le shéma suivant montre l'implémentation d'Adapter par agrégation.

Figure 3.3 le pattern Adapter par agrégation

C'est une version plus générale du pattern Adapter que la précédente car elle ne nécessite pas de langage authorisant l'héritage multiple.

En outre, si l'on réalise cette agrégation par pointeur (ou par référence), en passant cette donnée au constructeur de E, alors il possible d'adapter toute classe dérivée de A avec la seule classe Adapter E !

En effet, du fait que nous pratiquons par agrégation, il n'y a pas de relation privilégiée entre les classes A et E. Du coup, les méthodes de E sont obligées de passer par les méthodes publiques de A pour réaliser la moindre opération. Du coup, tout appel à une méthode polymorphe sera bien rétrocédé vers la bonne classe de destination. On ne le répètera jamais assez : la puissance du polymorphisme est infinie ! C'est très très cool.

3.2 Application au parc de véhicules

Vous l'aurez compris, il s'agit d'intégrer l'hélicoptère dans la hiérarchie de véhicule en ajoutant les méthodes nécessaires.

Afin de conserver une certaine homogénéité à l'ensemble, vous voudrez bien adopter les conventions suivantes :

Vous veillerez à réaliser les deux implémentations possible d'Adapter. Laquelle vous paraît meilleure ? un bon point pour vous si vous préférez celle par agrégation :).

Et surtout, souvenez vous de la règle suivante : le pattern Adapter est d'usage très fréquent et très simple : même si vous disposez du code source d'une classe, il vaut toujours mieux utiliser Adapter que modifier la classe existante, pensez un peu aux gens qui utilisent la classe telle qu'elle est maintenant !

Solution du TP

Le fichier Adapter.hxx contient les deux classes suivantes :

Signalons également que l'adaptation de la bonne vieille fonction srand à une utilisation au sein de la STL dans la classe foncteur CRand (fichier CRand.hxx) constitue également une forme (certes faible) du pattern Adapter.