Can the Visitor Pattern take additional parameters
Asked Answered
U

2

6

When implementing the Visitor Pattern, is it a bad idea to add additional parameters to the Accept and Visit methods? I have never seen any examples that do this but no mention of it being a bad idea either.

I would like to use this pattern in my domain model however additional parameters are required along with the entity itself.

eg -

public interface ISomethingVisitor
{
    void Visit(Foo foo, int p1, int p2);
}

public interface ISomethingVisitable
{
    void Accept(ISomethingVisitor visitor, int p1, int p2);
}
Underwaist answered 6/5, 2014 at 9:59 Comment(3)
And p1, p2 are the same for the whole visit?Stonefly
Hi @Stonefly yes they are. All sub-classes will require the same set of parameters for each visit.Underwaist
What if the visit/accept would be just a reference initializer, then you could add extra methods (with parameters) to the visitor that work on this reference. See this like a right to read the element at will.Typist
S
4

I'd say it's a bad idea. It might work fine for this visitor, but what happens when another visitor requires more/different parameters? If p1, p2 don't change, you can give them to the visitor at construction:

public class MyVisitor : ISomethingVisitor
{
    private int p1;
    private int p2;

    public MyVisitor(int p1, int p2)
    {
       _p1 = p1;
       _p2 = p2;
    }

    public void Visit(Foo foo)
    {
        //got access to _p1, _p2 here 
    }
}
Stonefly answered 6/5, 2014 at 10:14 Comment(7)
Thanks @weston. Out of curiosity - is this common practice.. to add extra properties and things to visitor implementations?Underwaist
Also, you mention that it may be problematic when implementing new visitors.. but in that situation wouldnt we be creating new Accept methods for each visitor anyway?Underwaist
What I mean is you can add a new ISomethingVisitor without changing anything else. Even if that new ISomethingVisitor implementation requires a p3.Stonefly
Yes I'd say it's perfectly normal to inject values/objects to a visitor so that it can do it's job. For example take a visitor that logs something about each visited item to a text log file. That would need to know a path to the file, unless you plan to hardcode it (yuk). Or even better, you can inject an object that does logging.Stonefly
Think of it this way: The visitor pattern is about double-dynamic dispatching. That really comes with the number of parameters: 'this' and 'Foo'. And, Visit is an interface as well. Every parameter ads exponential complexity to this design pattern. I would agree with weston: It's ill-advisedCalvano
what if they do change?Follicle
@Follicle not sure what you're askingStonefly
P
1

I'm doing something similar to this, but with Java. I'm facing the same issue where I want to pass some 'visit context' information to the visit, but my issue is that the 'Visitor' is stateless so only one visitor is created up front to service all threads (ie: all information will have to come through paramaters). I don't want to get into the business of thread local vars.

So, to the design of your interface, I'd suggest the following:

public interface ISomethingVisitor
{
    void Visit(Foo foo, VisitOptions params);
}

public interface ISomethingVisitable
{
    void Accept(ISomethingVisitor visitor, VisitOptions params);
}

In this way, you can define your VisitOptions params with 2 fields: p1 and p2, and if you want to add some paramaters later, no problem by adding those to your VisitOptions class...any existing code will just ignore they exist. You run into problems if you modify the VisitOptions by changing/removing parameters, but that's typical backwards-compatibility concerns.

Pricket answered 18/10, 2020 at 23:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.