use of visitor data pattern

I have been reading  a lot last few days about visitor data pattern but my head just can't digest it ;) on how to use it in my application. I came across a situation in my application code, where I think I might be able to make it more robust and efficient and visitor pattern came to mind. However I wasn't sure if I can apply it or not. I don't want use it just for the heck of using it ;)

Here's my existing design:
1) Virtual Base class with one pure virtual function:
        class Acc {     
                  virtual uint32_t common_method(uint32_t arg1, uint32_t arg2) = 0;
         };

2) There are 8 different classes derived from this Base class "Acc" and 
each of them has its own implementation of common_method(arg1, arg2);

        class Acc_Der_1 : public Acc;
        class Acc_Der_2 : public Acc;
        .........................
        .........................
        class Acc_Der_8 : public Acc;
       
3) One Factory class that returns an object of one of the above 8 classes
 based on some condition check.

        class Acc_factory {
            Acc* create_obj(uint32_t type) {
                   if (cond_1)
                       return new Acc_Der_1();
                   if (cond_2)
                       return new Acc_Der_2();
                   ........................ /// so on .....
                   if (cond_8)
                       return new Acc_Der_8();
            }
         }

4) Finally a manage class which invokes the actual virtual method. 

     class Acc_Manager {
          void main_func(uint32_t type) {
              std::auto_ptr<Acc*> acc_obj (Acc_factory::get_instance->create_obj(type))
              acc_obj->common_method(some_arg1, some_arg2); 
          }
 
      };

Open in new window


Now I need to extend my application to add 4 more derived classes from Acc
       class Acc_Der_9 : public Acc;
       class Acc_Der_10 : public Acc;
       class Acc_Der_11 : public Acc;
       class Acc_Der_12 : public Acc;

Each of them will have their own implementation of common_method(Arg1, arg2);

This will also force me to update the factory class to add 4 more condition check to return the correct derived class object.




Based on this requirement, is it feasible to use "Visitor Design Pattern". If so what are the pros and cons of it.
perlperlAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

perlperlAuthor Commented:
Hi evilrix, whenever you get a chance please look at this. I know you are the one of the expert in visitor patter ;)
0
evilrixSenior Software Engineer (Avast)Commented:
Looking...
0
evilrixSenior Software Engineer (Avast)Commented:
I don't think this problem is a good match for the visitor pattern. You're not looking to perform an downcast and that was what I specifically suggested using the visitor pattern for.

I do; however, dislike this type of code that attempts to reimplement the type-system that C++ already provides. Passing around a type at runtime, that you then have to resolve using a  switch (or, in your case a bunch of if statements) is just a runtime mechanism for implementing generics.

The C++ language already provides you a framework for doing this in the guise of templates. The difference is that templates, unlike passing around an integer value, are type safe and any errors will be caught at compile time rather than runtime.

In your case, I'd suggest you change the code to something like this...

typedef unsigned int uint32_t;

#include <memory>
#include <iostream>

class Acc {
public:
   virtual uint32_t common_method(uint32_t arg1, uint32_t arg2) = 0;
};

class Acc_Der_1 : public Acc {
public:
   uint32_t common_method(uint32_t arg1, uint32_t arg2) { return 1; }
};

class Acc_Der_2 : public Acc {
public:
   uint32_t common_method(uint32_t arg1, uint32_t arg2) { return 2; }
};

class Acc_Der_3 : public Acc {
public:
   uint32_t common_method(uint32_t arg1, uint32_t arg2) { return 3; }
};

class Acc_Der_4 : public Acc {
public:
   uint32_t common_method(uint32_t arg1, uint32_t arg2) { return 4; }
};

class Acc_Der_5 : public Acc {
public:
   uint32_t common_method(uint32_t arg1, uint32_t arg2) { return 5; }
};

class Acc_factory {
public:
   static
   Acc_factory * get_instance()
   {
      // Meyer's Singleton!
      static Acc_factory af;
      return &af;
   }

   // by only declaring the generic we ensure we can only create those
   // objects that we create specialised factory functions for (as below).
   template < typename T >
   Acc* create_obj();
};

// Specialised factory functions
template<>
Acc* Acc_factory::create_obj < Acc_Der_1>() {
   return new Acc_Der_1;
}

template<>
Acc* Acc_factory::create_obj < Acc_Der_2>() {
   return new Acc_Der_2;
}

template<>
Acc* Acc_factory::create_obj < Acc_Der_3>() {
   return new Acc_Der_3;
}

template<>
Acc* Acc_factory::create_obj < Acc_Der_4>() {
   return new Acc_Der_4;
}

template<>
Acc* Acc_factory::create_obj < Acc_Der_5>() {
   return new Acc_Der_5;
}

class Acc_Manager {
public:
   template <typename T>
   void main_func() {
      std::auto_ptr<Acc> acc_obj(Acc_factory::get_instance()->create_obj<T>());
      std::cout << acc_obj->common_method(0, 0) << std::endl;
   }
};

int main()
{
   Acc_Manager am;
   am.main_func<Acc_Der_1>();
   am.main_func<Acc_Der_2>();
   am.main_func<Acc_Der_3>();
   am.main_func<Acc_Der_4>();
   am.main_func<Acc_Der_5>();
}

Open in new window


Obviously, this is a contrived example but it was intended to be as simple as possible so you could follow the code. I hope this helps.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
sarabandeCommented:
you may use the factory pattern. then you can provide the create function with any new derived class and there is no need for enhancing a factory class.

3) One Factory class that returns an object of one of the above 8 classes
 based on some condition check.

typedef Acc* (*create_derived_acc)();
class Acc_factory {
    static std::map<std::string, create_derived_acc> factory;
public:
    static Acc* create_obj(const std::string &  classname) 
       {
            std::map<std::string, create_derived_acc>::iterator f;
            if ((f = factory.find(classname)) == factory.end())
            {
                   // class is not registered
                   return NULL;
            }
            create_derived_acc func = f->second;
            Acc* pacc = func();
            return pacc;
     }
     static add_create_func(const std::string & cn, create_derived_acc f)
     {
            factory[cn] = f;
     }
};

// acc_der_9.h
...
class Acc_Der_9 : public Acc
{
     static bool added_to_factory;
     ...
public:
     static Acc* create() { return new Acc_Der_9(); } 
     ...

// acc_der_9.cpp
...
#include "acc_der_9.h"

bool  Acc_Der_9::added_to_factory = Acc::add_create_func("Acc_Der_9", Acc_Der_9::create);
...

Open in new window


note, i used class name for key in factory, as it automatically is unique. of course you may change it (back) to uint32_t but that might violate the principle that a new class can be added solely by code of itself.

the new class will be "added" to factory by static initialization. after that you can create instances of the class by key.

Sara
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.