Can the visitor modify the object it visits
Asked Answered
B

4

6

When using the Visitor Pattern, can the visit(object) method update or modify the object it visits or is it simply supposed to only use the object in performing some computation and returning the computation result?

Thanks

Bolinger answered 16/9, 2017 at 23:38 Comment(0)
P
4

All examples of the visitor pattern I've seen don't change the objects visited.

But as far as I understand the definition given on Wikipedia, it's just not defined what the visitor can do with the visited objects.

Even the definition from Gang of Four (also in the wiki article) doesn't touch that subject:

Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

Therefore I'd say that a visitor may call any accessible method on an object it visits as this is not part of the visitor pattern - the visitor pattern just describes how this objects are made accessible.

Paradise answered 17/9, 2017 at 0:56 Comment(2)
(And ... indeed, I have used the Visitor pattern in cases where the purpose of the visit was to perform changes on the nodes of a graph.)Apron
I suppose to preserve the state of the element, the Observer pattern could be used instead? Although depending on how strictly you interpret the Observer pattern, the notifier may just indicate the state has changed and not the actual state itself. Is that right?Windom
L
1

In the following example the mailer is the "element" and the "visitor" is the lambda expression which is passed to send().

As you can see here (and in many other examples) the visitor can modify the element's internal state. That said, changing the element's internal state is not a requirement: it could be that the visitor will call some of the element's methods in order to do all sorts of actions: pass a message to another object, run a computation and print to screen the result and etc.

import java.util.function.Consumer;

public class Main {

    public static void main(String[] args) {
        Mailer.send(mailer ->
            mailer.from("[email protected]")
                    .to("[email protected]")
                    .body("what's up bud?")
        );
    }
}


class Mailer {

    String fromStr;
    String toStr;
    String bodyStr;

    public Mailer from(String from) {
        this.fromStr = from;
        return this;
    }

    public Mailer to(String to) {
        this.toStr = to;
        return this;
    }

    public Mailer body(String body) {
        this.bodyStr = body;
        return this;
    }

    public static void send(Consumer<Mailer> loader) {
        Mailer mailer = new Mailer();
        loader.accept(mailer);
        System.out.println(mailer);
        // ... send the email
    }

    @Override
    public String toString() {
        return "From: " + fromStr + "\n" +
                "To: " + toStr + "\n" +
                "Body: " + bodyStr;
    }
}
Leilani answered 17/9, 2017 at 0:26 Comment(0)
K
0

The visitor pattern is not meant to modify the object's state. Instead, its purpose is to implement specific functionality.

A paradigm would be adding the functionality of counting the elements of a tree, an example I explain in this Case Study: Applied Design Patterns and Software Architecture.

The CharacterVisitor which holds the count value of the total visited CustomCharacter class has the following structure:

/**
 * Implements the Visitor pattern
 */
class CharacterVisitor
{
    private int count = 0;

    void visitCharacter(CustomCharacter customCharacter)
    {
        count++;
    }

    public int getResult()
    {
        return count;
    }
}

The countCharacters() function, which implements the logic of the Visitor pattern:

/**
 * Counts the words in the text by using the Iterator and Visitor patterns.
 */
int countCharacters()
{
    CharacterVisitor characterVisitor = new CharacterVisitor();
    CharacterIterator characterIterator =
            new CharacterIterator(editorController.getCompositeBuilder());
    characterIterator.first();
    while(!characterIterator.isDone())
    {
        CustomCharacter customCharacter = characterIterator.getCurrent();
        customCharacter.accept(characterVisitor);
        characterIterator.next();
    }
    return characterVisitor.getResult();
}

Note that in this example I also implement the Iterator pattern as well. I go in to more details in the case study.

You can find the complete code in this github repository, where I explain all of the design patterns mentioned in the legendary GOF book.

Kiarakibble answered 17/9, 2017 at 0:26 Comment(6)
Many of the operations of a compiler would be unimplementable if this baseless rule was followed.Swiercz
Perhaps a clarification that I need to highlight in my answer would be what alfasin's answer mentions, that: "changing the element's internal state is not a requirement: it could be that the visitor will call some of the element's methods in order to do all sorts of actions"Kiarakibble
Perhaps when you wrote 'not meant to modify' you were wrong.Swiercz
Can you please provide a citation for that text you quoted at the start of the question? (Or if it is not a quotation, please justify the assertion.) Note that "modifying" and "implement specific functionality" are NOT contradictory. The "specific functionality" could include modification!!Apron
Thank you for your recommendation @StephenC. The GOF authors do not clarify whether object modification of the Visitor is acceptable or not. Joshua Bloch's (Effective Java) principle that every object should be preferably immutable in combination with GOF's reading lead me to what I stated in my personal quotation. I am trying to figure out how I can update my answer to clarify these ideas. Indeed modifying" and "implement specific functionality" are not contradictory.Kiarakibble
If a visitor can not modify the state of any of the objects it visits, what is the alternative solution? I see this as a valid scenario. Perhaps a 'modifying visitor' vs 'non-modifying' visitor.Bolinger
M
0

The visit(object) method is able to update or modify the object it visits. That said it is only able to update or modify fields or properties that are both public and not readonly on that class. Alternatively the visit method could use public methods that object exposes to update or modify the object.

Mosher answered 18/2, 2018 at 17:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.