Pattern Visiteur: Java vs Python

Duke, the Java Mascot, in the waving pose. Duk...

Image via Wikipedia

Le développement du moteur de génération de pyjama est plus long que prévu. Je le souhaitais extensible facilement mais avec le moins de dépendance externe possible. Après avoir jeté un oeil sur la version python de stringTemplate, j’en ai conclu que le besoin de templating de Pyjama pouvais se contenter de la classe standard string.Template de python. Nul besoin de dépendre d’une librairie externe.

Si le mécanisme de remplacement était trouvé, le moteur de génération restait encore à écrire. En effet dans mon esprit ce moteur doit pouvoir prendre en charge une modification du modèle de projet ou carrément de nouveau type de projet. Les notions de Template en tant que modèle de fichier, de Transformateur en tant qu’unité de transformation commencèrent a émerger, chacune étant indépendante l’une de l’autre et la première à priori fixe tandis que la seconde pouvant s’enrichir au grès des besoins de générations.

Les transformateurs sont appliqués à l’ensemble des templates et un transformateur donné doit agir différemment selon la nature du template. Par exemple le transformateur de source python ne doit pas agir sur le fichier logo du projet et inversement le transformateur de logo doit créer des logos de différentes tailles pour le bureau hildon mais ne pas agir sur les sources python ! Le pattern visiteur frappe à la porte.

Le pattern visiteur permet d’ajouter des comportements à un ensemble d’objet sans toucher aux objets eux-mêmes. Le visiteur ne sait pas sur qui il agit et c’est l’élément visité qui rappel le visiteur en indiquant qui il est, ainsi le visiteur peut appliquer le bon comportement.

Son implémentation la plus simple en Java est la suivante:

public interface IVisitor {
    public void visit(VisitedElement ve);
}

public interface IVisitable {
    public void accept(IVisitor v);
}

class VisitedElement implements IVisitable {
    public void accept(IVisitor visitor){
        visitor.visit(self)
    }
}

class Visitor implements IVisitor {
    public void visit(VisitedElement visiteElement){
       // faire algo spécific à VisitedElement
    }
 }

Ainsi pour appliquer un visiteur à un d’element il suffit de faire

IVisitable e = VisitedElement();
IVisitor v = Visitor();
e.accept(v);

Pour apliquer le visiteur à un ensemble d’élément de nature différente, il suffit d’appeler la méthode accept(IVisitor) de leur interface commune dont l’implémentation, identique dans chacune d’elle, appelle le visiteur en passant l’élément lui-même. Ici opère la magie du compilateur Java qui traduit cela par un appel à la méthode prenant un paramètre du type de l’élément. Ainsi le visiteur sait qui il visite !

Malheureusement en Python une méthode ou plus généralement une fonction ne se définie pas par sa signature (nom + paramètre) mais uniquement par son nom. En python la surcharge de fonction n’existe pas mais uniquement l’écrasement (la redéfinition). Ainsi il n’existe que une et une seule fonction portant un nom donné!

Cela nous empêche d’avoir une implémentation identique de la méthode accept(IVisitor). Les éléments doivent indiquer qui ils sont en appelant des méthodes nommées différemment.

 class IVisitable():
     def accept(self, visitor):
         pass

 class IVisitor():
     def visit_Element(self, e):
         pass

 class Element(IVisitable):
     def accept(self,visitor):
         visitor.visit_Element(self)

 class Visitor(IVisitor):
     def visit_Element(self, e):
         # action spécifique quand on gère un Element
         pass
Cet article, publié dans Application, Langage, est tagué , , . Ajoutez ce permalien à vos favoris.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s