Question

I have an algorithm that requires a large number of parameters (i.e. configuration) as part of its constructor and also requires some clearly defined creational steps. Therefore I have created a Builder Pattern implementation that allows to set the needed parameters and create the intermediate and final instance e.g.

// somewhere
class SomeAlgo { 
    public:
       SomeAlgo(double a, double b, double c, double d, double e /* etc */);
;

Now I define the Builder to be e.g.

class SomeAlgoBuilder {
    public:
      SomeAlgo& createResult() { /* TODO: */ }

      virtual SomeAlgoBuilder& creationStep1() = 0;
      virtual SomeAlgoBuilder& creationStep2() = 0;
      virtual SomeAlgoBuilder& creationStep3() = 0;

      // example setter note the builder returns *this
      SomeAlgoBuilder& setA(double a) { a_ = a; return *this; } 
      SomeAlgoBuilder& setB(double b) { b_ = b; return *this; } 
      // etc 
};

At this point everything looks ok but now I would like to Pull Up the setters of the builder into a SomeAlgoConfig class so that I can also cover the use-case of passing around a simple configuration instead of a convoluted long list of parameters. This simple configuration is what in Java is known as a Value Object or Bean. The new Builder would be like this:

// not "is a" config but need the implementation inheritance 
// >>>>>> note the need to pass SomeAlgoBuilder as template
class SomeAlgoBuilder : private SomeAlgoConfig<SomeAlgoBuilder> {
    public:
      SomeAlgo& createResult() { /* TODO: */ }

      virtual SomeAlgoBuilder& creationStep1() = 0;
      virtual SomeAlgoBuilder& creationStep2() = 0;
      virtual SomeAlgoBuilder& creationStep3() = 0;
};

Now the SomeAlgoConfig implementation:

template<T>  
class SomeAlgoConfig {
      T& setA(double a) { a_ = a; return *static_cast<T*>(this); } 
      T& setB(double b) { b_ = b; return *static_cast<T*>(this); } 
      // etc 
}

and the intent is to be used like this:

SomeAlgoConfig config; // <<< here it won't compile because it misses the T parameter
config.setA(a).setB(b).setC(c);

This will do the trick I guess. However, whenever I'd like to use SomeAlgoConfig on its own (outside the context of a Builder) e.g. to pass it as parameter I need to declare it with a template parameter which would be itself SomeAlgoConfig<SomeAlgoConfig>. How can I define it in a way that it defaults to itself as template type? e.g. doing this doesn't work: template<typename T = SomeAlgoConfig> class SomeAlgoConfig because the SomeAlgoConfig is not yet known at that point.

Was it helpful?

Solution

Config should be like a container for parameters, so you don't have to change constructors and setters whenever you change your mind about the parameters you want to pass. Making builder inherit config makes no sense, because builder isn't a config and "I need inherited methods" isn't a valid argument to implement this in your design. You could make config a member of the builder and call:

builder.getConfig().setA(a);
builder.getConfig().setB(b);
//...
builder.createResult();

If you want to have a template config, you'd make the builder template as well, for example:

template<class T>
class AlgoBuilder<T>{
//...
private:
AlgoConfig<T> config;

That way, you can set pass the config in the constructor.

About your question on missing the T parameter when instantiating the config... Well, at that point, since you want to set a, b ,c and all the other parameters, you already know the type of parameters, so you can actually instantiate the config with the T type, which is the same type of your parameters. AlgoConfig< AlgoConfig> doesn't make much sense to me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top