Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A more generic visitor pattern

I'm sorry if my question is so long and technical but I think it's so important other people will be interested about it

I was looking for a way to separate clearly some softwares internals from their representation in c++

I have a generic parameter class (to be later stored in a container) that can contain any kind of value with the the boost::any class

I have a base class (roughly) of this kind (of course there is more stuff)

class Parameter 
{
public:
    Parameter()
    template typename<T> T GetValue() const { return any_cast<T>( _value ); }
    template typename<T> void SetValue(const T& value) { _value = value; }
    string GetValueAsString() const = 0;
    void SetValueFromString(const string& str) const = 0;
private:
    boost::any _value;
}

There are two levels of derived classes: The first level defines the type and the conversion to/from string (for example ParameterInt or ParameterString) The second level defines the behaviour and the real creators (for example deriving ParameterAnyInt and ParameterLimitedInt from ParameterInt or ParameterFilename from GenericString)

Depending on the real type I would like to add external function or classes that operates depending on the specific parameter type without adding virtual methods to the base class and without doing strange casts

For example I would like to create the proper gui controls depending on parameter types:

Widget* CreateWidget(const Parameter& p)

Of course I cannot understand real Parameter type from this unless I use RTTI or implement it my self (with enum and switch case), but this is not the right OOP design solution, you know.

The classical solution is the Visitor design pattern http://en.wikipedia.org/wiki/Visitor_pattern

The problem with this pattern is that I have to know in advance which derived types will be implemented, so (putting together what is written in wikipedia and my code) we'll have sort of:

struct Visitor 
{
  virtual void visit(ParameterLimitedInt& wheel) = 0;
  virtual void visit(ParameterAnyInt& engine) = 0;
  virtual void visit(ParameterFilename& body) = 0;
};

Is there any solution to obtain this behaviour in any other way without need to know in advance all the concrete types and without deriving the original visitor?


Edit: Dr. Pizza's solution seems the closest to what I was thinking, but the problem is still the same and the method is actually relying on dynamic_cast, that I was trying to avoid as a kind of (even if weak) RTTI method

Maybe it is better to think to some solution without even citing the visitor Pattern and clean our mind. The purpose is just having the function such:

Widget* CreateWidget(const Parameter& p)

behave differently for each "concrete" parameter without losing info on its type

like image 745
martjno Avatar asked Aug 28 '08 09:08

martjno


People also ask

Why is it called Visitor pattern?

The Visitor pattern represents an operation to be performed on the elements of an object structure without changing the classes on which it operates. This pattern can be observed in the operation of a taxi company. When a person calls a taxi company (accepting a visitor), the company dispatches a cab to the customer.

What does a Visitor pattern do?

In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures.

Is generics a design pattern?

In software engineering world, Factory Design Pattern is used to encapsulate object creation. Generics which is another useful concept, converts runtime typecast errors to compile-time errors. Besides these benefits, Factory Design Pattern and Generics provide a simple approach to manage software problems.

Is Visitor pattern is a Behaviour pattern?

Visitor design pattern is one of the behavioral design patterns. It is used when we have to perform an operation on a group of similar kind of Objects. With the help of visitor pattern, we can move the operational logic from the objects to another class.


1 Answers

For a generic implementation of Vistor, I'd suggest the Loki Visitor, part of the Loki library.

like image 108
Josh Avatar answered Sep 22 '22 19:09

Josh