Éditer sur GitHub

Visitor

Problème

Nous disposons d'une hiérarchie et nous souhaitons pouvoir profiter du polymorphisme en dehors de la hiérarchie.

Cas d'école

Nous avons une hiérarchie représentant des géométries et nous souhaitons pouvoir réaliser facilement des traitements en dehors de la hiérarchie sans avoir à tester le type comme suit :

if ( geometry instanceof Point ){
    Point point = (Point)geometry;
    // traiter le cas Point
}else if ( geometry instanceof LineString ){
    LineString lineString = (LineString)geometry;
    // traiter le cas LineString
}else{
    throw new RuntimeException("geometry type not supported");
}

Solution

interface GeometryVisitor {

    public void visit( Point point ) ;

    public void visit( LineString lineString ) ;

}
interface Geometry {
    public void accept(GeometryVisitor visitor);
}
class Point implements Geometry {
    public void accept(GeometryVisitor visitor){
        visitor.visit(this);
    }
}

Ainsi, nous pourrons externaliser les traitements de la hiérarchie sans perdre l'intérêt du polymorphisme :

class GeometryRenderer implements GeometryVisitor {

    public void visit( Point point ){
        System.out.println("Render Point");
    }

    public void visit( LineString lineString ) {
        System.out.println("Render LineString");
    }

}

A l'usage :

Geometry geometry = /* Point ou LineString ou Polygon */
GeometryRenderer renderer = new GeometryRenderer();
geometry.accept(renderer);

Comment ça marche?

La méthode accept convertit un polymorphisme par héritage en polymorphisme paramétrique.

Remarques

Extension des hiérarchies

L'utilisation du patron visiteur peut bloquer l'ajout de nouveau type à la hiérarchie dans un code client.

Capacité des langages

Nous devrons adapter l'implémentation en fonction des capacités des différents langages en matière de polymorphisme paramétrique.

Variantes

visitor.visit(Visitable a, Visitable b);

Liens utiles