Question

D'après le code que je l'ai trouvé, il semble que le visiteur doit connaître la structure des objets visités et faire appel aux enfants nécessaires. Cela semble un peu maladroit dans certains cas où le visiteur voudrait continuer à travailler même si les classes visitées sont modifiées.

Je suppose que la vraie question est: est-leur un modèle où l'énumération se fait par le code visité plutôt que le code de visiteur

Était-ce utile?

La solution

L'objet visiteur est nécessaire de connaître la structure des choses qu'il visite. C'est OK, bien. Vous êtes supposé pour écrire des opérations de visite spécialisées pour chaque type de chose que le visiteur sait comment visiter. Cela permet au visiteur de décider combien il veut vraiment visiter, et dans quel ordre.

Supposons que vous ayez un arbre. Un visiteur peut faire un traversal pré-commande, on peut faire une dans l'ordre traversal, et encore un autre visiteur peut agir que sur les nœuds de feuilles. Les classes de visiteurs peuvent faire toutes ces choses sans nécessiter de modifications à la classe des arbres.

Le visiteur connaît la structure, mais cela ne signifie pas nécessairement l'opération le visiteur effectue connaît toute la structure. Vous pouvez combiner un visiteur avec une commande . Offrir le visiteur objet un objet de commande, et le visiteur invoquera la commande sur chaque chose qu'il visite.

Si vous voulez avoir une opération simple et de laisser la collection vous donner chaque élément à agir, alors vous voulez que la collection fournir une iterator pour lui-même. Appelez votre fonction sur chaque chose que le iterator vous donne.

Si vous voulez itérer sur les noeuds dans divers ordres de l'arbre, l'arbre devra offrir plusieurs itérateurs. Si vous voulez traiter les noeuds dans un ordre que l'arbre ne supporte pas déjà, vous devrez modifier la classe d'arbre.

Autres conseils

Oui. Les objets visités peuvent faire l'énumération (par exemple appel aux enfants nécessaires). Ceci est encore appelé le modèle « Visiteur » (en fait, Design Pattern premier échantillon de 'du visiteur, il fait de cette façon). Mon exemple maquillé extrait:

public void accept(Visitor visitor) {
  for (Node n : children) {
    n.accept(visitor);
  }
}

Note: pour visiter les enfants, nous ne pouvons pas dire visitor.visit(n);. Ceci est parce que Java ne sélectionne pas dynamiquement la méthode (en fonction de la classe d'exécution de ses arguments), mais sélectionne la méthode statique (par le type de ses arguments à la compilation).

En bref mots, je pense que modèle des visiteurs est orthogonale à l'énumération façon de faire. Il peut être fait de toute façon, ou aucune énumération du tout.

Je pense que le visiteur est nécessaire de savoir quels éléments la structure visités se compose de. Savoir que la voiture se compose de roues et moteur. Pour savoir exactement comment ils sont combinés est pas nécessaire, je pense. Considérons l'exemple suivant. Insider connaît la structure de l'objet visité et effectue lui-même l'énumération. Outsider ne le sait pas et les délégués de dénombrement à l'objet visités.

interface Visitable {
    void accept(Visitor visitor);
}

class WorkingRoom implements Visitable {
    public int number;
    WorkingRoom(int number) {
        this.number = number;
    }

    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

class BossRoom implements Visitable {
    public String bossName;
    BossRoom(String bossName) {
        this.bossName = bossName;
    }
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

interface Visitor{
    void visit(WorkingRoom workingRoom);
    void visit(BossRoom bossRoom);
    void visit(Office office);
}

class Office implements Visitable{
    public Visitable[] firstFloor;
    public Visitable[] secondFloor;
    public Visitable ceoRoom;
    public Office(){
        firstFloor = new Visitable[]{ new WorkingRoom(101),
                                        new WorkingRoom(102),
                                        new BossRoom("Jeff Atwood"),
                                        new WorkingRoom(103)};
        secondFloor = new Visitable[]{  new WorkingRoom(201),
                                        new WorkingRoom(202),
                                        new BossRoom("Joel Spolsky")};

        ceoRoom = new BossRoom("Bill Gates");
    }

    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public void showMeTheOffice(Visitor visitor, boolean sayPlease) {
        // Office manager decides the order in which rooms are visited
        for(int i=secondFloor.length-1; i >= 0; i--){
            secondFloor[i].accept(visitor);
        }
        if (sayPlease){
            ceoRoom.accept(visitor);
        }
        for (int i = 0; i < firstFloor.length; i++) {
            firstFloor[i].accept(visitor);
        }
    }
}

class Insider implements Visitor{
    public void visit(WorkingRoom workingRoom) {
        System.out.println("I> This is working room #"+workingRoom.number);
    }

    public void visit(BossRoom bossRoom) {
        System.out.println("I> Hi, "+bossRoom.bossName);
    }

    public void visit(Office office) {
        // I know about office structure, so I'll just go to the 1st floor
        for(int i=0;i<office.firstFloor.length;i++){
            office.firstFloor[i].accept(this);
        }
    }
}

class Outsider implements Visitor{

    public void visit(Office office) {
        // I do not know about office structure, but I know they have a 
        // nice office manager
        // I'll just ask to show me the office
        office.showMeTheOffice(this, true);
    }

    public void visit(WorkingRoom workingRoom) {
        System.out.println("O> Wow, room #"+workingRoom.number);
    }

    public void visit(BossRoom bossRoom) {
        System.out.println("O> Oh, look, this is "+bossRoom.bossName);
    }
}

public class Main{
    public static void main(String[] args) {
        Office office = new Office(); // visited structure
        // visitor who knows about office structure
        Insider employee = new Insider(); 
        office.accept(employee);
        System.out.println();
        // visitor who does not know about exact office structure
        // but knows something else
        Outsider candidate = new Outsider(); 
        office.accept(candidate);

        // no enumeration at all, but still a visitor pattern
        Visitable v = new BossRoom("Linus Torvalds");
        v.accept(candidate);
    }
}

J'ai eu un projet avec une large utilisation du modèle des visiteurs sans aucune énumération du tout. Nous avions une interface de base sur le terrain et de nombreuses classes sa mise en œuvre, comme Stringfield, NumberField, etc. Nous avions très souvent à faire des choses différentes en fonction du type de terrain, par exemple rendre d'une manière différente, la charge de DB, l'exportation vers XML, etc. . Nous pourrions définir des méthodes dans l'interface terrain, mais ce serait faire couplé à chaque élément du projet - domaine pauvre doit savoir sur l'exportation, l'importation, ce qui rend html et rtf, etc. on pourrait aussi utiliser instanceof, mais un ensemble de possibles les classes implémentant l'interface domaine a été changé au fil du temps et il était possible d'ajouter un nouveau type de champ et d'oublier d'ajouter

else if (field instanceof NewlyAddedFieldType) {...}

quelque part. Nous avons donc décidé d'utiliser les habitudes des visiteurs, et il était comme

Visitor v = new XMLExportVisitor(outputStream);
field.accept(v);

Comme toute mise en œuvre sur le terrain est nécessaire pour avoir la méthode

void accept(FieldVisitor visitor)

puis si j'ajouter une nouvelle implémentation de l'interface domaine, je dois la mettre en œuvre en quelque sorte. Normalement, il est

visitor.visit(this);

lorsque cela est une classe nouvellement ajouté. Cela me force à ajouter

void visit(NewlyAddedClass visited);

à l'interface FieldVisitor, qui me fait mettre en œuvre dans chaque mise en œuvre FieldVisitor que nous avons déjà. Donc, si j'oublie de faire quelque chose de - je vais erreur du compilateur. Énumération dans ce cas, le cas échéant, a été faite en dehors de la structure et le visiteur visité. Mais je pense encore comme un cas valide de motif de visiteur. Il happend être un peu plus difficile à mettre en œuvre, mais plus facile et plus sûr à utiliser.

Le explique une approche différente où il ajoute des événements pour entrer et quitter les niveaux. associée présente des arguments pour l'itération étant dans le visiteur ou le conteneur. Il comprend une suggestion d'utiliser un itérateur externe qui fait sens pour moi si vous avez un arbre régulier et à itérer différemment.

Rétrospectivement à mon visiteur oofRep il y avait une série de niveaux de différentes classes à visiter et avait l'itération dans les méthodes comme:

void
oofRepVisitor::VisitViewHeaders(oofRepBandList& inBands)
{
    VisitBandList(inBands);
}


void
oofRepVisitor::VisitBandList(oofRepBandList& inBands)
{
    EnterLevel();
    const unsigned long numBands = inBands.count();
    for (unsigned long i=0; i<numBands; i++) {
        oofRepBand* theBand = inBands.value(i);
        assert(theBand);
        VisitTypedBand(theBand);
    }
    LeaveLevel();
}

avec une valeur de remplacement

void
OOF_repXMLlayoutVisitor::VisitViewHeaders(oofRepBandList& inBands)
{
    oofRepStreamEnv::out() << mIdentities.getIndentString();
    if (inBands.keepTogether())
        oofRepStreamEnv::out()  << "<header>\n";    
    else  // default is ON, and simplifies XML
        oofRepStreamEnv::out()  << "<header keepTogether='false'>\n";
    VisitBandList(inBands);
    oofRepStreamEnv::out() 
        << mIdentities.getIndentString()
        << "</header>\n";
}

Jetez un oeil à l'explication dans ce de .

De Wiki :

  

Dans la programmation orientée objet et   génie logiciel, le visiteur   modèle de conception est un moyen de séparation   un algorithme à partir d'une structure d'objet   sur lequel il opère. Une pratique   résultat de cette séparation est la   possibilité d'ajouter de nouvelles opérations   structures d'objet existant sans   la modification de ces structures. Ainsi,   en utilisant le modèle des visiteurs aide à   conformité avec l'état ouvert / fermé   principe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top