Hi, I want to know if there is a design pattern for specifying options to a set of algorithms. I am using C++. Let me describe my problem. I am having a set of algorithms and these algorithms have different options. I want to design a single point access to these algorithms. Something similar to a strategy pattern. This single point access is a controller class which takes input as a generic options class. Depending upon the options, a suitable algorithm will be used. I want to generalize these options so that i can extend algorithms and the client. Thanks, Amol
An often-used pattern is to create a policy class which is passed as a template type to your class and then inherited from privately:
template <typename Policy>
class fancy_algorithm : private Policy {
};
One famous example of this is the std::allocator
class which is often inherited in that manner:
template <typename T, typename Alloc = std::allocator<T> >
class my_container : private Alloc {
public:
typedef Alloc allocator;
// It's necessary to make the base class names available explicitly.
typedef typename allocator::pointer pointer;
using allocator::construct;
// …
};
I agree with Konrad on policy-based design. I also recommend Modern C++ Design: Generic Programming and Design Patterns Applied. After this book your vision of C++ will be changed forever ;)
Building on Konrad's suggestion of using policy types, if your algorithms require parameters at construction time, you can handle this cleanly by requiring that any Policy
class has a nested type called Params
, and then provide a constructor inside fancy_algorithm<Policy>
that takes an argument of this type and passes it to the contained Policy
object:
template <typename Policy>
class fancy_algorithm : private Policy {
public:
typedef typename Policy::Params Params; // Need to redeclare :(
explicit fancy_algorithm(Params params = Params()) : Policy(params) {}
};
Any relevant parameters need to be packaged into a single object of type Policy::Params
.
The Policy
class is always constructed with a single argument of type Policy::Params
. To work with policy classes that (may) require no parameters, provide a default constructor (or use the implicitly declared one) in Params
, not in Policy
. This way, by using a default value for the fancy_algorithm<Policy>
constructor as above, we enable convenient default-construction of a fancy_algorithm<Policy>
whenever Policy::Params
has a default constructor (i.e. when the Policy
doesn't require any parameters). No safety is lost: if Policy::Params
lacks a default constructor (indicating that some parameters are required), any attempt to default-construct a fancy_algorithm<Policy>
object will fail at compile time.
Example:
struct multiply_by_params {
multiply_by_params(int x /* = 42 */) : _x(x) {} // See bottom
int get() const { return _x; } // Or, just make multiply_by a friend
private:
int _x;
};
struct multiply_by {
typedef multiply_by_params Params;
multiply_by(Params p) : _x(p.get()) { /* Other initialisation */ }
// Other code implementing the strategy (e.g. an operator()())
...
private:
int _x;
};
fancy_algorithm<multiply_by> a(69); // Always compiles
fancy_algorithm<multiply_by> b; // Compiles iff /* = 42 */ is uncommented