I V wrote:
ma740988 wrote:
[.......]
What exactly is the problem you are trying to solve? If you're just
asking a theoretical question, then the theoretical answer is simple:
"don't do that" (that is, don't create a factory which creates classes
with no common interface). If you have a particular use in mind, then
people may be able to suggest alternative designs if you give us more
detail.
You're right . I'm not so sure the factory is a good idea here.
Here's my initail attempt. Two classes wanting to run different
algorithms...
#include <iostream>
#include <vector>
#include <map>
#include <numeric>
#include <deque>
#define MEAN1 1
#define MEAN2 2
#define MEAN3 3
#define MEAN4 4
#define MEAN5 5
#define MEAN6 6
using namespace std;
typedef deque <double> DOUBLE_QUEUE;
class AbstractAlgorithm{
public:
virtual double run(const DOUBLE_QUEUE& queue) = 0;
};
class Mean1: public AbstractAlgorithm{
public:
double run(const DOUBLE_QUEUE& queue){
double val = accumulate ( queue.begin(), queue.end(), 0. ) /
queue.size();
cout << val << " ";
return val;
}
};
class Mean2: public AbstractAlgorithm{
public:
double run(const DOUBLE_QUEUE& queue){
double val = accumulate ( queue.begin(), queue.end(), 0. ) /
queue.size();
cout << val << " ";
return val;
}
};
class Mean3: public AbstractAlgorithm{
public:
double run(const DOUBLE_QUEUE& queue){
double val = accumulate ( queue.begin(), queue.end(), 0. ) /
queue.size();
cout << val << " ";
return val;
}
};
class Mean4: public AbstractAlgorithm{
public:
double run(const DOUBLE_QUEUE& queue){
double val = accumulate ( queue.begin(), queue.end(), 0. ) /
queue.size();
cout << val << " ";
return val;
}
};
class Mean5: public AbstractAlgorithm{
public:
double run(const DOUBLE_QUEUE& queue){
double val = accumulate ( queue.begin(), queue.end(), 0. ) /
queue.size();
cout << val << " ";
return val;
}
};
class Mean6: public AbstractAlgorithm{
public:
double run(const DOUBLE_QUEUE& queue){
double val = accumulate ( queue.begin(), queue.end(), 0. ) /
queue.size();
cout << val << " ";
return val;
}
};
class Algorithms{
private:
map<int,AbstractAlgorithm*> _registeredAlgorithms;
public:
void registerAlgorithm(const int name, AbstractAlgorithm* alg){
_registeredAlgorithms[name]=alg;
}
double run(const int name, const DOUBLE_QUEUE& queue){
_registeredAlgorithms[name]->run(queue);
}
};
class MultipleCallAlgorithm{
friend ostream &operator<<(ostream &str, MultipleCallAlgorithm c);
private:
vector<int> _v;
Algorithms _a;
public:
MultipleCallAlgorithm(const Algorithms a){
this->_a = a;
}
void registerAlgorithm(const int s){
_v.push_back(s);
}
void runRegistered(const DOUBLE_QUEUE& queue){
vector<int>::iterator iter;
for(iter = _v.begin() ; iter != _v.end() ; iter++)
_a.run(*iter,queue);
}
double run(const int name, const DOUBLE_QUEUE &queue ){
_a.run(name,queue);
}
};
class YingYang{
private:
MultipleCallAlgorithm* _a;
public:
YingYang(MultipleCallAlgorithm* a){
this->_a = a;
}
void registerAlgorithm(const int name){
_a->registerAlgorithm(name);
}
void runRegistered(const DOUBLE_QUEUE& queue){
_a->runRegistered(queue);
}
};
main(){
Algorithms a;
// Algorithm registration
a.registerAlgorithm(MEAN1, new Mean1());
a.registerAlgorithm(MEAN2, new Mean2());
a.registerAlgorithm(MEAN3, new Mean3());
a.registerAlgorithm(MEAN4, new Mean4());
a.registerAlgorithm(MEAN5, new Mean5());
a.registerAlgorithm(MEAN6, new Mean6());
YingYang ying(new MultipleCallAlgorithm(a));
ying.registerAlgorithm(MEAN1);
ying.registerAlgorithm(MEAN3);
ying.registerAlgorithm(MEAN6);
YingYang yang(new MultipleCallAlgorithm(a));
yang.registerAlgorithm(MEAN1);
yang.registerAlgorithm(MEAN4);
yang.registerAlgorithm(MEAN5);
// Example data
DOUBLE_QUEUE q;
q.push_back(3);
q.push_back(4);
q.push_back(5);
q.push_back(6);
q.push_back(7);
ying.runRegistered(q);
yang.runRegistered(q);
}
So that was my initial attempt to determine how the factory could help
me here. That's fine except in reality each MEAN function differs in
the number of arguments. Well the factory _blew_ up, so now i'm
thinking ... - but first NOTE: MEAN is 'for demostration purpose'..
My real algorithms is FFT's IFFTs, BEM, MEAN etc. Both classes Ying
and Yang will run a subset of each .. meaning I know in advacen what to
run. An incoming message from the 'outside' world is what tells me the
sequence to run them. That's irrelevant though. Based on the code
above assume Yang should run MEAN1, MEAN4 and MEAN5. Assume Ying will
run MEAN1, MEAN3 and MEAN6. Assume MEAN1 takes two arguments, MEAN3
takes 5 arguments, MEAN6 takes 4 arguments.
That aside, I'm thinking I'm down to two options:
1. - One "Algorithms" class per client-class
- Algorithm registration will occur BEFORE class creation, but each
client class will have a copy of each algorithm (duplicates).
- As all the Algorithms classes must have the same interface, there are
two options:
a) fixed number of registerable functions (example: Algorithms
interface will be: alg1, alg2 and alg3, executing mean1, mean 3 and
mean 5 for Ying and mean1,mean 4 and mean 5 for Yang).
2. A generic interface where client classes refer to algorithms by
name. This means a
separate "MultipleCall algorithm" for each client class. This bothers
me though, so maybe I can try mixing both options, and use
"Centralized algorithm list" and "Algoritm registration". This way I
have flexibility and a single AlgorithmHelper class. The only drawback
here is a little more complicated interface - which I'm not sure how to
put together.
So ultimately I could have
class Ying:
algorithms.run(MEAN1,data1);
algorithms.run(MEAN3,different_data);
algorithms.run(MEAN6,different_data);
class Yang:
algorithms.run(MEAN1,data1);
algorithms.run(MEAN4,different_data);
algorithms.run(MEAN5,different_data);
Design 'decisions' (alot more involved than putting together a foo
class - if you follow what I'm saying) tend to be a little over my head
right now so I'm struggling with putting together both options.