I'm working on a code which needs to be extremely flexible in nature, i.e. especially very easy to extend later also by other people. But I'm facing a problem now about which I do not even know in principal how to properly deal with:
I'm having a rather complex Algorithm
, which at some point is supposed to converge. But due to its complexity there are several different criteria to check for convergence, and depending on the circumstances (or input) I would want to have different convergence criteria activated. Also it should easily be possible to create new convergence criteria without having to touch the algorithm itself. So ideally I would like to have an abstract ConvergenceChecker
class from which I can inherit and let the algorithm have a vector of those, e.g. like this:
//Algorithm.h (with include guards of course)
class Algorithm {
//...
vector<ConvergenceChecker*> _convChecker;
}
//Algorithm.cpp
void runAlgorithm() {
bool converged=false;
while(true){
//Algorithm performs a cycle
for (unsigned i=0; i<_convChecker.size(); i++) {
// Check for convergence with each criterion
converged=_convChecker[i]->isConverged();
// If this criterion is not satisfied, forget about the following ones
if (!converged) { break; }
}
// If all are converged, break out of the while loop
if (converged) { break; }
}
}
The problem with this is that each ConvergenceChecker
needs to know something about the currently running Algorithm
, but each one might need to know totally different things from the algorithm. Say the Algorithm
changes _foo
_bar
and _fooBar
during each cycle, but one possible ConvergenceChecker
only needs to know _foo
, another one _foo
and _bar
, and it might be that some day a ConvergenceChecker
needing _fooBar
will be implemented. Here are some ways I already tried to solve this:
- Give the function
isConverged()
a large argument list (containing_foo
,_bar
, and_fooBar
). Disadvantages: Most of the variables used as arguments will not be used in most cases, and if theAlgorithm
would be extended by another variable (or a similar algorithm inherits from it and adds some variables) quite some code would have to be modified. -> possible, but ugly - Give the function
isConverged()
theAlgorithm
itself (or a pointer to it) as an argument. Problem: Circular dependency. - Declare
isConverged()
as a friend function. Problem (among others): Cannot be defined as a member function of differentConvergenceChecker
s. - Use an array of function pointers. Does not solve the problem at all, and also: where to define them?
- (Just came up with this while writing this question) Use a different class which holds the data, say
AlgorithmData
havingAlgorithm
as a friend class, then provide theAlgorithmData
as a function argument. So, like 2. but maybe getting around circular dependency problems. (Did not test this yet.)
I'd be happy to hear your solutions about this (and problems you see with 5.).
Further notes:
- Question title: I'm aware that 'strongly dependent classes' already says that most probably one is doing something very wrong with designing the code, still I guess a lot of people might end up with having that problem and would like to hear possibilities to avoid it, so I'd rather keep that ugly expression.
- Too easy?: Actually the problem I presented here was not complete. There will be a lot of different
Algorithm
s in the code inheriting from each other, and theConvergenceChecker
s should of course ideally work in appropriate cases without any further modification even if newAlgorithm
s come up. Feel free to comment on this as well. - Question style: I hope the question is neither too abstract nor too special, and I hope it did not get too long and is understandable. So please also don't hesitate to comment on the way I ask this question so that I can improve on that.