I am working on code that should be extremely flexible in nature, especially very easy to extend later by other people. But now I am faced with a problem that I don’t even know in principle how to deal with:
I have a rather complicated Algorithm , which at some point should converge. But because of its complexity, there are several different criteria for checking convergence, and depending on the circumstances (or input) I would like to have different convergence criteria. It is also easy to create new convergence criteria without having to touch the algorithm itself. Therefore, ideally, I would like to have an abstract class ConvergenceChecker from which I can inherit, and let the algorithm have a vector of these, for example. eg:
//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 is that every ConvergenceChecker needs to know something about the current start of Algorithm , but each of them may need to know completely different things from the algorithm. Say the Algorithm changes _foo _bar and _fooBar during each cycle, but one of the possible ConvergenceChecker should know only _foo , another _foo and _bar , and maybe some day a ConvergenceChecker needing _fooBar . Here are some of the ways that I have already tried to solve:
- Give the
isConverged() function a list of large arguments (containing _foo , _bar and _fooBar ). Disadvantages: most of the variables used as arguments will not be used in most cases, and if the Algorithm extends to another variable (or a similar algorithm inherits from it and adds some variables), then some code should be changed, → perhaps, but ugly - Give the
isConverged() function to the Algorithm itself (or a pointer to it) as an argument. Problem: circular dependence. - Declare
isConverged() as a friend function. Problem (among other things): cannot be defined as a member function from different ConvergenceChecker 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 when writing this question). Use another class that contains data, e.g.
AlgorithmData , having Algorithm as a class other, then select AlgorithmData as a function argument. So, as 2. but perhaps circumvent the circular problems of addiction. (Not tested it yet.)
I would be happy to hear your decisions about this (and the problems you see with 5).
Further notes:
- Question heading: I know that “highly dependent classes” already say that most likely someone is doing something very bad when developing the code, but I think that many people may run into this problem and would like to hear the possibilities to avoid this, so I would rather keep that ugly expression.
- Too easy: In fact, the problem I presented here was incomplete. The code that inherits from each other will have many different
Algorithm , and ConvergenceChecker should work perfectly in appropriate cases without any further modifications, even if a new Algorithm appears. Feel free to comment on this. - Question style: I hope this question is not too abstract and not too special, and I hope that it is not too long and clear. So please also feel free to comment on how I ask this question so that I can improve it.
source share