2.2. Ajout de traitements▲
Dans cette section, nous allons nous intéresser à un pattern particulier: le pattern Visitor, qui permet de séparer de manière très simple les données et les traitements associés.
2.2.1. Visitor▲
Le pattern Visiteur permet une séparation précise entre données et traitements. Il est le compagnon idéal du pattern Composite.
Avec le pattern Visiteur, on obtient 2 hiérarchies distinctes :
- la hiérarchie des objets support de données
- la hiérarchie des Visiteurs (contenant les traitements sur les données)
D'un point de vue implémentation, cela nous donne :
void
ObjetDeTypeA::
accept( Visitor *
v ) {
v->
visitObjetDeTypeA( this
) ;
}
void
MonVisiteur::
visitObjetDeTypeA( ObjetDeTypeA *
objet ) {
// Traitement d'un objet de type A
}
void
MonVisiteur::
visitObjetDeTypeB( ObjetDeTypeB *
objet ) {
// Traitement d'un objet de type B
}
void
MonVisiteur::
visitObjetDeTypeC( ObjetDeTypeC *
objet ) {
// Traitement d'un objet de type C
}
Pour appliquer un visiteur, on procède de la sorte :
unObjet->
accept( unVisiteur ) ;
Voici alors ce qu'il se passe (admettons que unObjet soit de type ObjetDeTypeA) :
- la méthode accept de ObjetDeTypeA est appelée
- la méthode visitObjetDeTypeA du visiteur v est alors appelée avec comme paramètre this (notre objet de type ObjetDeTypeA)
- on entre alors dans le corps de la méthode visitObjetDeTypeA du visiteur. Le paramètre obj fait référence à l'objet de type ObjetDeTypeA sur lequel on applique notre traitement
Intérêt du pattern Visitor :
Pour ajouter un traitement à notre application, il suffit donc de créer un nouveau Visiteur avant de surcharger les méthodes permettant de visiter les différents objets de la hierarchie. Ensuite, pour utiliser le visiteur, on fait:
monObjet->
accept( monVisiteur ) ;
De cette manière, on peut facilement ajouter de nouveaux traitements sans toucher à la hiérarchie de nos objets (en POO "classique", on aurait implémenté de nouvelles méthodes pour ajouter de nouvelles fonctionnalités). Grâce aux Visiteurs :
- le code est plus clair (des fonctionnalités différentes se trouvent dans des Visiteurs différents)
- des équipes différentes peuvent travailler sur des fonctionnalités différentes sans gêner les autres équipes
- on n'est pas obligé de tout recompiler à chaque ajout d'une fonctionnalité (seul le code du Visiteur est recompilé)
Exemple d'application :
Imaginons que nous ayons une scène 3D, représentée à l'aide du pattern Composite. On peut vouloir choisir plusieurs modes d'affichage pour cette scène 3D: aperçu en fils de fer, non texturé, texturé et avec différents effets (bump mapping, anti-aliasing...), ou photo-réaliste au moyen de lancés de rayons. Pour cela, on met en place des Visiteurs spécifiques à chaque mode d'affichage. Cela permet de structurer le programme et de pouvoir facilement ajouter de nouvelles fonctionnalités (ex: calculer la complexité d'une scène) par simple ajout de Visiteurs.