2

I often have a class where I want to allow a functionality to be selected. For example I have a class that has a GetNextNode() function which is used like MyClass::DoIteration(){GetNextNode(); } . I want to allow the user to select from one of many possible implementations of GetNextNode to determine how the next node to process should be determined. I also want to allow a user of my code to easily provide their own implementation.

So far, the answer is to make GetNextNode() virtual and re-implement it subclasses of MyClass...

My problem arises when I have two such interchangeable functions. If I have Function1() and Function2() which both have N possible implementations, then I would have to provide 2N subclasses to allow the user to pick which pair of these functions to use. Generally, it is much worse (if there are more than 2 such functions).

Note that these functions need access to data inside MyClass.

Is there a "pattern" that I am missing that allows "plugins" like this to be selected?

Michael Petrotta
  • 59,888
  • 27
  • 145
  • 179
David Doria
  • 9,873
  • 17
  • 85
  • 147
  • Hey David, You should specify whether you need these functions to be interchangeable at compile-time or at run-time. At compile time, this would most likely be done with a Policy class as template argument. At run-time, this would be either a visitor pattern or a composition of interfaces. – Mikael Persson Feb 26 '11 at 19:14

4 Answers4

3

Actually I think what he's looking for is Policy based design, see http://en.wikipedia.org/wiki/Policy-based_design.

EDIT:

Example, (obviously doesn't compile, but hopefully you get the idea. You provide a template parameter for IterationPolicy, and it's expected to be a class that provides a getNextNode function. You can provide a default policy and a variety of alternate policies with your class. Also the user can write their own, provided they implement the appropriate interface. Avoids the problems associated with inheritance.

template <typename IterationPolicy = DefaultIterationPolicy>
class class X {
    IterationPolicy iterationPolicy;
    void DoIteration() { iterationPolicy.getNextNode(); }
};
Kevin
  • 24,871
  • 19
  • 102
  • 158
0

Have you looked at the visitor pattern?

Stephan
  • 1,007
  • 7
  • 9
0

You can offer the different implementations as protected functions.

...
protected:
Node GetNextNode_Method1();
Node GetNextNode_Method2();
public:
Node GetNextNode();
...

The final class can override GetNextNode() to apply one of the offered alternatives.

linepogl
  • 9,147
  • 4
  • 34
  • 45
  • This is quite simple, but actually may work the best for my use case since I need so much access to the MyClass variables and functions. I would just make GetNextNode() pure virtual and force the user to select an implementation by implementing a GetNextNode() that simply calls one of the existing GetNextNode_Method1() type functions, or implementing their own. – David Doria Feb 26 '11 at 19:34
0

This looks like the Strategy Pattern Edit: And if you only need compile time variations, the Policy-based design you disovered yourself can be more appropriate.

class NextNodeStrategy {
    public:
     virtual int GetNextNode() = 0;
};

class MyClass {
   private:
   NextNodeStrategy &nextNode;
   public:
     void SetNextNodeStrategy(NextNodeStrategy &strategy)
     {
         nextNode = strategy;
     } 
     void DoIteration() 
     {
        nextNode.GetNextNode();
     }
};

The strategy might need access to other stuff, so you might need to pass in something to GetNextNode, now that the implementation lives in a separte class, and you might want to provide a default implementation of it (e.g. just have MyClass inherit from NextNodeStrategy , and set nextNode = this; in the MyClass constructor.

If you have other things that also can be changed, you make a strategy out of that too, and the 2 can vary independently.

nos
  • 223,662
  • 58
  • 417
  • 506
  • Yea, the problem is with the "need access to other stuff." The GetNextNode function needs several data and function members of MyClass. – David Doria Feb 26 '11 at 19:31
  • Then pass them in as arguments, or give them as constructor arguments when you create the NextNodeStrategy objects. – nos Feb 26 '11 at 19:42