Edge Rewrite
// request.cf · coarse context

A page that knows where it met you.

Only coarse request metadata is shown. This demo does not display or persist visitor IP addresses.

Country
US
Cloudflare location
CMH
Connection
HTTP/2
Language
Not provided

Ray ID: a21c5cbb0851879c

Jump to content

Single-serving visitor pattern

From Wikipedia, the free encyclopedia

In computer programming, the single-serving visitor pattern is a design pattern. Its intent is to optimise the implementation of a visitor that is allocated, used only once, and then deleted (which is the case of most visitors).

Applicability

[edit]

The single-serving visitor pattern should be used when visitors do not need to remain in memory. This is often the case when visiting a hierarchy of objects (such as when the visitor pattern is used together with the composite pattern) to perform a single task on it, for example counting the number of cameras in a 3D scene.

The regular visitor pattern should be used when the visitor must remain in memory. This occurs when the visitor is configured with a number of parameters that must be kept in memory for a later use of the visitor (for example, for storing the rendering options of a 3D scene renderer).

However, if there should be only one instance of such a visitor in a whole program, it can be a good idea to implement it both as a single-serving visitor and as a singleton. In doing so, it is ensured that the single-serving visitor can be called later with its parameters unchanged (in this particular case "single-serving visitor" is an abuse of language since the visitor can be used several times).

Usage examples

[edit]

The single-serving visitor is called through the intermediate of static methods.

Without parameters, this is SingleServingVisitor::applyTo(e);, while with parameters, it is SingleServingVisitor::applyTo(e, a, b);.

If implemented as a singleton:

SingleServingVisitor::setA(a);
SingleServingVisitor::setB(b);
SingleServingVisitor::applyTo(e);

Consequences

[edit]

Pros

[edit]
  • No "zombie" objects. With a single-serving visitor, it is ensured that visitors are allocated when needed and destroyed once useless.
  • A simpler interface than visitor. The visitor is created, used and free by the sole call of the applyTo() static method.

Cons

[edit]
  • Repeated allocation. At each call of the applyTo() method, a single-serving visitor is created then discarded, which is time-consuming. In contrast, the singleton only performs one allocation.

Implementation

[edit]

Basic implementation (without parameters)

[edit]
template <typename A, typename B>
class SingleServingVisitor {
protected:
    SingleServingVisitor() = default;
public:
    ~SingleServingVisitor() = default;

    static void applyTo(Element& e) {
        e.accept(SingleServingVisitor<A, B>());
    }

    virtual void visitA(A& a) = 0;
    virtual void visitB(B& b) = 0;
};

Passing parameters

[edit]

If the single-serving visitor has to be initialised, the parameters have to be passed through the static method:

static void applyTo(Element& elem, const A& a, const B& b)  {
    elem.accept(SingleServingVisitor<A, B>(a, b));
}

Implementation as a singleton

[edit]

This implementation ensures:

  • that there is at most one instance of the single-serving visitor
  • that the visitor can be accessed later
template <typename A, typename B>
class SingleServingVisitor {
protected:
    A a;
    B b;

    SingleServingVisitor() = default;

    // Note: instance() method need not to be public
    static SingleServingVisitor& instance() noexcept {
        static SingleServingVisitor ssv;
        return ssv;
    }
public:
    ~SingleServingVisitor() = default;

    static void applyTo(Element& e) noexcept {
        e.accept(instance());
    }

    // static methods to access parameters
    static void setA(const A& a) noexcept {
        this->a = a;
    }

    static void setB(const B& b) noexcept {
        this->b = b;
    }

    virtual void visitA(A& a) = 0;
    virtual void visitB(B& b) = 0;
};
[edit]