Search code examples
c++optimizationtheory

Theoretical c++ OO Strategy code


Lets say I have a piece of code:

A1 a;
A2 b;
a= function1_A();
b= function2_A();

And then I want to do it in another way:

B1 a;
B2 b;
a= function1_B();
b= function2_B();

And I do a Strategy Design Pattern to have both and decide wich one I want. But the thing is the code is the same with the exeption of all the A are now B. Of course what that does may be compleatly different but that's out of the scope.

Is there a way to design the code in order to prevent such repetition?

If it was just functions I know I could do it with a abstract superclass and have it

a=function1_SUPER();

and then each have the correct implementation like:

function1_SUPER(){ function1_A();}

but that still generates a lot of code. Plus doesn't work with classes names like changing the A1 to B1 right?


Solution

  • I would compose the problem in the two parts I see: first, distiguishing by type (A1, A2 vs. B1, B2) and second, distinguishing by the initialization of the variables. Since you say, the code is all the same but the types aren't templates come to mind. So my first attempt would be:

    template <class X1, class X2>
    struct MyStrategy {
      void foo()
      {
        X1 a = /* create appropiate X1 */;
        X2 b = /* create appropiate X2 */;
        // code that is the same for both except for the types...
      }
    };
    

    Of course the function would have parameters and/or return type, but you get the gist.

    Now to the second part, the one I left in comments: initialization of the values. I would achieve that by some kind of policy based design. First sketch:

    template <class X1, class X2>
    struct X1X2Creator;
    
    template <> 
    struct X1X2Creator<A1, A2> {
      A1 createX1() { return function1_A(); }
      A2 createX2() { return function2_A(); }
    };
    
    template <> 
    struct X1X2Creator<B1, B2> {
      B1 createX1() { return function1_B(); }
      B2 createX2() { return function2_B(); }
    };
    
    
    template <class X1, class X2>
    struct MyStrategy : X1X2Creator<X1, X2> {
      void foo()
      {
        X1 a = this->createX1();
        X2 b = this->createX2();
        // code that is the same for both except for the types...
      }
    };
    

    Note you have to call the create-functions via this->createX1(), due to their dependent names, otherwise the compiler should complain. You could as well explicitly qualify the functions (X1X2Creator<X1, X2>::createX1()).

    You can improve that design by your needs, e.g. by not using inheritance but instantiating a X1X2Creator and calling the functions or making them static. If you want to use more combinations of different types, use one creation policy per type:

    template <class X1, class X2>
    struct MyStrategy {
      void foo()
      {
        X1 a = CreationPolicy<X1>::create();
        X2 b = CreationPolicy<X2>::create();
        // code that is the same for both except for the types...
      }
    };
    

    If you want to be able to use different policies for the same types, provide the policie classes as template parameters:

    template <class X1, class X2, 
      class X1Creator = CreationPolicy<X1>,
      class X2Creator = CreationPolicy<X2>>
    struct MyStrategy {
      void foo()
      {
        X1 a = X1Creator::create();
        X2 b = X2Creator::create();
        // code that is the same for both except for the types...
      }
    };
    

    HTH