Domanda

In base al codice che ho trovato, sembra che il visitatore è tenuto a conoscere la struttura degli oggetti visitati e chiamare sui bambini necessari. Questo sembra un po 'goffo, in alcuni casi in cui il visitatore vorrebbe continuare a lavorare, anche se le classi visitati vengono modificati.

Credo che la vera domanda è:? è il loro un modello in cui l'enumerazione è fatto dal codice visitato piuttosto che il codice visitatore

È stato utile?

Soluzione

L'oggetto visitatore è necessarie per conoscere la struttura delle cose che visita. Va bene, però. Tu sei dovrebbe per le operazioni di scrittura visita specializzati per ogni tipo di cosa che il visitatore sappia visitare. Questo permette al visitatore di decidere quanto si vuole davvero da visitare, e in quale ordine.

Supponiamo di avere un albero. Un visitatore potrebbe fare un attraversamento pre-ordine, si potrebbe fare un attraversamento in ordine, e ancora un altro visitatore potrebbe agire solo su nodi foglia. Le classi visitatore può fare tutte queste cose senza dover apportare modifiche alla classe albero.

Il visitatore conosce la struttura, ma questo non significa necessariamente che l'operazione il visitatore esegue conosce tutta la struttura. Si potrebbe combinare un visitatore con un comando . Dare al visitatore oggetto un oggetto di comando, e il visitatore potrà richiamare il comando su ogni cosa che visita.

Se si desidera avere una semplice operazione e lasciare che la raccolta darvi ogni elemento di agire su, poi si desidera la raccolta per fornire un iteratore per se stessa. Chiama la funzione su ogni cosa che l'iteratore ti dà.

Se si desidera iterare i nodi del albero in vari ordini, allora l'albero avrà bisogno di offrire molteplici iteratori. Se si desidera elaborare i nodi in un ordine che l'albero non sia già supporta, è necessario modificare la classe albero.

Altri suggerimenti

Sì. Gli oggetti visitati possono fare l'enumerazione (cioè chiamata sui bambini necessari). Questo si chiama ancora il modello di "Visitatore" (in realtà, Design Pattern 's primo campione di visitatori lo fa in questo modo). Il mio made-up frammento di esempio:

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

Nota: per visitare i bambini, non si può dire visitor.visit(n);. Questo perché Java non seleziona dinamicamente il metodo (in base alla classe di esecuzione dei suoi argomenti), ma seleziona il metodo statico (in base al tipo in fase di compilazione dei suoi argomenti).

In parole brevi, penso che modello visitatore è ortogonale al modo in cui l'enumerazione è fatto. Si può fare in entrambi i casi, o nessuna enumerazione a tutti.

Credo che visitatore è tenuto a conoscere quali elementi la struttura visitata consiste. Piacere sapere che auto si compone di Ruote e motori. Per sapere esattamente come sono combinati non è necessario, credo. Consideriamo seguente esempio. Insider sa struttura dell'oggetto visitato e si esegue enumerazione. Outsider non lo sa e delegati enumerazione dell'oggetto visitato.

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);
    }
}

Ho avuto un progetto con uso largo del modello visitatore senza alcuna enumerazione a tutti. Abbiamo avuto interfaccia di base Campo e molte classi sua attuazione, come StringField, NumberField, ecc Molto spesso abbiamo dovuto fare cose diverse in base al tipo di campo, ad esempio, lo rendono in un modo diverso, carico da DB, l'esportazione in XML, ecc . potremmo definire metodi in un'interfaccia campo, ma che renderebbe accoppiato con ogni singola caratteristica del progetto - campo poveri deve sapere sull'esportazione, l'importazione, il rendering di hTML e RTF, ecc Abbiamo anche potuto utilizzare instanceof, ma insieme di possibili le classi che implementano l'interfaccia campo è stato cambiato nel corso del tempo ed è stato possibile aggiungere nuovo tipo di campo e dimenticare di aggiungere

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

da qualche parte. Così abbiamo deciso di usare modello visitatore, ed era come

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

Come qualsiasi implementazione campo è richiesto di avere il metodo

void accept(FieldVisitor visitor)

se poi aggiungo nuova implementazione di interfaccia di campo, devo implementare in qualche modo. Normalmente è

visitor.visit(this);

dove questa è una classe appena aggiunta. Questo mi costringe a aggiungere

void visit(NewlyAddedClass visited);

all'interfaccia FieldVisitor, che mi fa implementarlo in ogni implementazione FieldVisitor che già abbiamo. Quindi, se mi dimentico di fare qualcosa di questo - Prendo errore del compilatore. Enumeration in questo caso, se del caso, è stato fatto al di fuori della struttura visitata e visitatore. Ma io continuo a pensare a questo proposito come un caso di valida modello visitatore. E 'successo a essere un po' più difficile da implementare, ma più facile e sicuro da usare.

gerarchica Visitor spiega un approccio diverso in cui si aggiunge eventi per entrare e uscire livelli. La presenta argomenti per l'iterazione essere all'interno il visitatore o il contenitore. Esso comprende un suggerimento di utilizzare un iteratore esterna che ha un senso per me se si dispone di un albero normale e necessario iterare in maniera diversa.

Guardando indietro alla mia oofRep visitatore aveva una serie di livelli classi di diversi per visitare e aveva l'iterazione all'interno dei metodi come:

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();
}

con un override

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";
}

Date un'occhiata alla spiegazione in questo .

Wiki :

  

Nella programmazione orientata agli oggetti e   ingegneria del software, il visitatore   design pattern è un modo di separare   un algoritmo di profilo d'oggetto   su cui opera. Un pratico   risultato di questa separazione è la   possibilità di aggiungere nuove operazioni di   strutture degli oggetti esistenti senza   modificando tali strutture. Così,   utilizzando il modello visitatore aiuta   conformità con l'apertura / chiusura   linea di principio.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top