Template:Notability Template:Use dmy dates 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).

ApplicabilityEdit

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 examplesEdit

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

  • Without parameters:<syntaxhighlight lang="cpp">
Element* elem;
SingleServingVisitor::apply_to(elem);

</syntaxhighlight>

  • With parameters:<syntaxhighlight lang="cpp">
Element* elem;
TYPE param1, param2;
SingleServingVisitor::apply_to(elem, param1, param2);

</syntaxhighlight>

  • Implementation as a singleton:<syntaxhighlight lang="cpp">
Element* elem;
TYPE param1, param2;
SingleServingVisitor::set_param1(param1);
SingleServingVisitor::set_param2(param2);
SingleServingVisitor::apply_to(elem);

</syntaxhighlight>

ConsequencesEdit

ProsEdit

  • 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 apply_to static method.

ConsEdit

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

Implementation (in C++)Edit

Basic implementation (without parameters)Edit

<syntaxhighlight lang="cpp"> // Declaration class Element; class ElementA; class ElementB; class SingleServingVisitor;

... // Same as with the visitor pattern.

// Definition class SingleServingVisitor { protected:

   SingleServingVisitor();

public:

   ~SingleServingVisitor();
   static void apply_to(Element*);
   virtual void visit_ElementA(ElementA*) = 0;
   virtual void visit_ElementB(ElementB*) = 0;

}

// Implementation void SingleServingVisitor::apply_to(Element* elem) {

   SingleServingVisitor ssv;
   elem.accept(ssv);

} </syntaxhighlight>

Passing parametersEdit

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

<syntaxhighlight lang="cpp"> void SingleServingVisitor::apply_to(Element* elem, TYPE param1, TYPE param2, ...) {

   SingleServingVisitor ssv(param1, param2, ...);
   elem.accept(&ssv);

} </syntaxhighlight>

Implementation as a singletonEdit

This implementation ensures:

  • that there is at most one instance of the single-serving visitor
  • that the visitor can be accessed later

<syntaxhighlight lang="cpp"> // Definition class SingleServingVisitor { protected:

   static SingleServingVisitor* instance_;
   TYPE param1_;
   TYPE param2_;
   SingleServingVisitor();
   static SingleServingVisitor* get_instance();
   // Note: get_instance method does not need to be public

public:

   ~SingleServingVisitor();
   static void apply_to(Element*);
   // static methods to access parameters
   static void set_param1(TYPE);
   static void set_param2(TYPE);
   virtual void visit_ElementA(ElementA*) = 0;
   virtual void visit_ElementB(ElementB*) = 0;

}

// Implementation SingleServingVisitor* SingleServingVisitor::instance_ = NULL;

SingleServingVisitor* SingleServingVisitor::get_instance() {

   if (this->instance_ == NULL)
       this->instance_ = new SingleServingVisitor();
   return this->instance_;

}

void SingleServingVisitor::apply_to(Element* elem) {

   elem->accept(get_instance());

}

void SingleServingVisitor::set_param1(TYPE param1) {

   getInstance()->param1_ = param1;

}

void SingleServingVisitor::set_param2(TYPE param2) {

   getInstance()->param2_ = param2;

} </syntaxhighlight>

Related patternsEdit