views:

191

answers:

4

Setting:
A pseudo-random pattern has to be generated. There are several ways / or algorithms availible to create different content. All algorithms will generate a list of chars (but could be anything else)... the important part is, that all of them return the same type of values, and need the same type of input arguments.

It has to be possible to call a method GetRandomPattern(), which will use a random one of the algorithms everytime it is called.

My first aproach was to put each algorithm in it's own function and select a random one of them each time GetRandompattern() is called. But I didn't come up with another way of choosing between them, than with a switch case statement which is unhandy, ugly and inflexible.

class PatternGenerator{
 public:
  list<char> GetRandomPattern();
 private:
  list<char>GeneratePatternA(foo bar);
  list<char>GeneratePatternB(foo bar);
  ........
  list<char>GeneratePatternX(foo bar);
}

What would be a good way to select a random GeneratePattern function every time the GetRandomPattern() method is called ?

Or should the whole class be designed differently ?

Thanks a lot

+9  A: 

Create a single class for each algorithm, each one subclassing a generator class. Put instances of those objects into a list. Pick one randomly and use it!

More generically, if you start creating several alternative methods with the same signature, something's screaming "put us into sibling classes" at you :)

Update Can't resist arguing a bit more for an object-oriented solution after the pointer-suggestion came

  • Imagine at some point you want to print which method created which random thing. With objects, it's easy, just add a "name" method or something. How do you want to achieve this if all you got is a pointer? (yea, create a dictionary from pointers to strings, hm...)
  • Imagine you find out that you got ten methods, five of which only differ by a parameter. So you write five functions "just to keep the code clean from OOP garbage"? Or won't you rather have a function which happens to be able to store some state with it (also known as an object?)
  • What I'm trying to say is that this is a textbook application for some OOP design. The above points are just trying to flesh that out a bit and argue that even if it works with pointers now, it's not the future-proof solution. And you shouldn't be afraid to produce code that talks to the reader (ie your future you, in four weeks or so) telling that person what it's doing
Nicolas78
Putting member function pointers in the list would be simpler than wrapping each one in a class.
Mike Seymour
ok that's what happens to me after spending most of my time in Java and C# instead of C++ ;) However, since (s)he's already using a class, I think it's worth pointing out (no pun intended) how a proper OOP solution would look like.
Nicolas78
@nicolas78Your answer is very reasonable, but I had hoped to find a way to do it without creating a new class for each algorithm cause it would mean a lot of code lines distracting from the algorithm in c++
zitroneneis
@Mike SeymourI will have a look into member function pointers. Thanks for the advice
zitroneneis
updated answer with a few arguments for objects :)
Nicolas78
@nicolas78: Indeed, if the problem were more complicated then your suggestion might be the best approach (although in some cases function objects might be better still). But C++ is a multiparadigm language, and you won't get the most from it if you treat every problem as an exercise in object-oriented design.
Mike Seymour
+1  A: 
vnm
+1 for some actual code
Nicolas78
+5  A: 

You can make an array of function pointers. This avoids having to create a whole bunch of different classes, although you still have to assign the function pointers to the elements of the array. Any way you do this, there are going to be a lot of repetitive-looking lines. In your example, it's in the GetRandomPattern method. In mine, it's in the PatternGenerator constructor.

#define FUNCTION_COUNT 24
typedef list<char>(*generatorFunc)(foo);

class PatternGenerator{
    public:
        PatternGenerator() {
            functions[0] = &GeneratePatternA;
            functions[1] = &GeneratePatternB;
            ...
            functions[24] = &GeneratePatternX;
        }
        list<char> GetRandomPattern() {
            foo bar = value;
            int funcToUse = rand()%FUNCTION_COUNT;
            functions[funcToUse](bar);
        }
    private:
        generatorFunc functions[FUNCTION_COUNT];
}
Eric Finn
I think this is the simplest solution (though using function objects where you can pass parameters to the constructor may also simplify things if a bunch of these pattern generation functions use the same algorithm with different parameters). You can also define the `functions` array as `std::tr1::function<list<char>(foo)> functions[FUNCTION_COUNT]` if you want a simple way to put both function pointers and function objects in a single array.
Ken Bloom
+1  A: 

Thank you for all your great input. I decided to go with function pointers, mainly because I didn't know them before and they seem to be very powerfull and it was a good chance to get to know them, but also because it saves me lot of lines of code.

If I'd be using Ruby / Java / C# I'd have decided for the suggested Strategy Design pattern ;-)

class PatternGenerator{
 typedef list<char>(PatternGenerator::*createPatternFunctionPtr);
public:
 PatternGenerator(){
  Initialize();
   }
 GetRandomPattern(){
  int randomMethod = (rand()%functionPointerVector.size());
  createPatternFunctionPtr randomFunction = functionPointerVector.at( randomMethod );
  list<char> pattern = (this->*randomFunction)();
  return pattern;
  }
private:
  void Initialize(){
   createPatternFunctionPtr methodA = &PatternGenerator::GeneratePatternA;
   createPatternFunctionPtr methodB = &PatternGenerator::GeneratePatternB;
   ...
   functionPointerVector.push_back( methodA );
   functionPointerVector.push_back( methodB );
   }
  list<char>GeneratePatternA(){
   ...}
  list<char>GeneratePatternB(){
   ...}
  vector< createPattern > functionPointerVector;

The readability is not much worse as it would have been with the Design Pattern Solution, it's easy to add new algorithms, the pointer arithmetics are capsuled within a class, it prevents memory leaks and it's very fast and effective...

zitroneneis
You'd be better off putting the pointers in a `vector` rather than a `list`, so it's both quicker and easier to access a random element. (`randomFunction = functionPointers[randomIndex]` instead of your use of `advance`).
Mike Seymour
thank you for the advice, I will change my implementation
zitroneneis
And maybe it's just a typo, but the random index should be `rand() % size()`, not `rand() + size()`.
Mike Seymour
thanks again=) it was a typo
zitroneneis
ok I agree it looks good and "talks" well about what it does
Nicolas78