Visitor pattern with multiple argument

Erik Sapir

Is it possible to implement the visitor pattern such that:

  1. Multiple visitors can be used on the acceptor.

  2. The acceptor must not change when new visitors are added.

  3. Visitors might have to receive arguments and the number and types of arguments are different between visitors.

An example is a Shape hierarchy class and operations that can be performed on the shapes. If the operations does not have to receive any arguments, than each operation can be a visitor and inherit from Visitor class, and each shape will implement the accept method:

void SomeShape::accept(Visitor* visitor)
{
    visitor->visit(*this);
}

However, is there a way to use the visitor pattern in case each visitor need to receive additional arguments? Are there any good alternatives?

Quentin

You'll want to store your additional parameters in the Visitor itself. They are usually passed in the constructor. That's called reification ("making real") : what would have been a function call with parameters is now an object, representing the function call, and storing the parameters. You can now pass this object around without looking inside, which is what we want.

Your accept function should take a Visitor const& so that you can pass it temporaries, which is handy :

pShape->accept(SnapToPoint(x, y));

The SnapToPoint class will look like that :

struct SnapToPoint : Visitor {
    SnapToPoint(float x, float y) : _point(x, y) {}

    void visit(Circle   &c) const override { /* Use _point on c */ }
    void visit(Triangle &t) const override { /* Use _point on t */ }
    void visit(Square   &s) const override { /* Use _point on s */ }

private:
    Point _point;
};

Edit: In response to the dependency injection need below, an example of a Visitor Factory :

struct ShapeOperationFactory {
    virtual std::unique_ptr<Visitor> snapToPoint(float x, float y) const = 0;
};

struct MyShapeOpFactory : ShapeOperationFactory {
    std::unique_ptr<Visitor> snapToPoint(float x, float y) const override {
        return std::unique_ptr<Visitor>(new SnapToPoint(x, y));
    }
};

Which would be called like that :

ShapeOperationFactory *pFactory = /* Get a factory */;
pShape->accept(pFactory->snapToPoint(4.0f, 7.0f));

See it working here. Note that I had to take Visitor instances by std::unique_ptr this time, since the factory is generic.

Edit 2: Refreshed my memory about temporaries lifetime. I've rolled back the accept function to taking a Visitor const&, see results here.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related