Patrons de conception/Visiteur

Un livre de Wikilivres.
Aller à : navigation, rechercher
Patrons de conception
Patrons de conception
Sommaire
Patron de conception
Catégorie: « Gang of Four »Comportement
Nom français : Visiteur
Nom anglais : Visitor
Découpler classes et traitements, afin de pouvoir ajouter de nouveaux traitements sans ajouter de nouvelles méthodes aux classes existantes


Un visiteur est le nom d'une des structures de patron de conception comportemental.

Le visiteur est une manière de séparer un algorithme d'une structure de données. Un visiteur possède une méthode par type d'objet traité. Pour ajouter un nouveau traitement, il suffit de créer une nouvelle classe dérivée de la classe Visiteur. On n'a donc pas besoin de modifier la structure des objets traités, contrairement à ce qu'il aurait été obligatoire de faire si on avait implémenté les traitements comme des méthodes de ces objets.

L'avantage du patron visiteur est qu'un visiteur peut avoir un état. Ce qui signifie que le traitement d'un type d'objet peut différer en fonction de traitements précédents. Par exemple, un visiteur affichant une structure arborescente peut présenter les nœuds de l'arbre de manière lisible en utilisant une indentation dont le niveau est stocké comme valeur d'état du visiteur.

Exemples[modifier | modifier le wikitexte]

C++[modifier | modifier le wikitexte]

Prenons une classe ObjetPere, de laquelle hériteront Objet1, Objet2 et Objet3, elles posséderont la méthode accept(Visitor v).

void ObjetDeType1::accept( Visitor * v )
{
    v->visitObjetDeType1( this );
}

Créons la classe Visitor, dont hériteront Visiteur1 et Visiteur2. Dans chacun de ces objets, on retrouvera une méthode visiterObjet1(Objet1 a), visiterObjet2(Objet2 b) et visiterObjet3(Objet3 c).

void MonVisiteur::visitObjetDeType1( ObjetDeType1 * objet )
{
    // Traitement d'un objet de type 1
}
 
void MonVisiteur::visitObjetDeType2( ObjetDeType2 * objet )
{
    // Traitement d'un objet de type 2
}
 
void MonVisiteur::visitObjetDeType3( ObjetDeType3 * objet )
{
    // Traitement d'un objet de type 3
}

Java[modifier | modifier le wikitexte]

L'exemple suivant montre comment afficher un arbre de nœuds (les composants d'une voiture). Au lieu de créer des méthodes d'affichage pour chaque sous-classe (Wheel, Engine, Body, et Car), une seule classe est créée (CarElementPrintVisitor) pour afficher les éléments. Parce que les différentes sous-classes requièrent différentes actions pour s'afficher proprement, la classe CarElementPrintVisitor répartit l'action en fonction de la classe de l'argument qu'on lui passe.

interface CarElementVisitor
{
    void visit(Wheel wheel);
    void visit(Engine engine);
    void visit(Body body);
    void visitCar(Car car);
}
 
interface CarElement
{
    void accept(CarElementVisitor visitor);
    // Méthode à définir par les classes implémentant CarElements
}
 
class Wheel implements CarElement
{
    private String name;
 
    Wheel(String name)
    {
        this.name = name;
    }
 
    String getName()
    {
        return this.name;
    }
 
    public void accept(CarElementVisitor visitor)
    {
        visitor.visit(this);
    }
}
 
class Engine implements CarElement
{
    public void accept(CarElementVisitor visitor)
    {
        visitor.visit(this);
    }
}
 
class Body implements CarElement
{
    public void accept(CarElementVisitor visitor)
    {
        visitor.visit(this);
    }
}
 
class Car
{
    CarElement[] elements;
 
    public CarElement[] getElements()
    {
        return elements.clone(); // Retourne une copie du tableau de références.
    }
 
    public Car()
    {
        this.elements = new CarElement[]
            {
                new Wheel("front left"),
                new Wheel("front right"),
                new Wheel("back left"),
                new Wheel("back right"),
                new Body(),
                new Engine()
            };
    }
}
 
class CarElementPrintVisitor implements CarElementVisitor
{
    public void visit(Wheel wheel)
    {
        System.out.println("Visiting "+ wheel.getName() + " wheel");
    }
 
    public void visit(Engine engine)
    {
        System.out.println("Visiting engine");
    }
 
    public void visit(Body body)
    {
        System.out.println("Visiting body");
    }
 
    public void visitCar(Car car)
    {
        System.out.println("\nVisiting car");
        for(CarElement element : car.getElements())
        {
            element.accept(this);
        }
        System.out.println("Visited car");
    }
}
 
class CarElementDoVisitor implements CarElementVisitor
{
    public void visit(Wheel wheel)
    {
        System.out.println("Kicking my "+ wheel.getName());
    }
 
    public void visit(Engine engine)
    {
        System.out.println("Starting my engine");
    }
 
    public void visit(Body body)
    {
        System.out.println("Moving my body");
    }
 
    public void visitCar(Car car)
    {
        System.out.println("\nStarting my car");
        for(CarElement carElement : car.getElements())
        {
            carElement.accept(this);
        }
        System.out.println("Started car");
    }
}
 
public class VisitorDemo
{
    static public void main(String[] args)
    {
        Car car = new Car();
 
        CarElementVisitor printVisitor = new CarElementPrintVisitor();
        CarElementVisitor doVisitor = new CarElementDoVisitor();
 
        printVisitor.visitCar(car);
        doVisitor.visitCar(car);
    }
}

Lien externe[modifier | modifier le wikitexte]