473,382 Members | 1,376 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,382 software developers and data experts.

factory design question..

Consider:

#include "handyfactory.h"
#include <iostream>

struct Shape
{
virtual void print() const=0;
};
struct Square: public Shape
{
void print() const
{
cout<<"I am square, hear me roar!" <<endl;
}
};
struct Triangle: public Shape
{
void print() const
{
cout<<"I am triangle, hear me roar!" <<endl;
}
};
int main()
{
Factory::reg<Shape, Square>("square");
Factory::reg<Shape, Triangle>("triangle");
Factory::make<Shape>("triangle")->print();

}
-----handyfactory.h-----
#include <map>
#include <string>
using namespace std;
struct Factory
{
template<typename T>
static map<string, T *> &getMap()
{
static map<string, T *> mp;
return mp;
}

template <typename T>
struct Creator
{
virtual T * make()=0;
};
template <typename T1, typename T2>
struct CreatorSub: public Creator<T1>
{
virtual T1 * make()
{
return new T2;
}
};
template <typename T1, typename T2>
static void reg(string const &str)
{
(getMap<Creator<T1> >())[str]=new CreatorSub<T1, T2>;
}
template <typename T>
static T* make(const string &str)
{
return getMap<Creator<T> >()[str]->make();
}
};

Now the factory appears to be ideal considering the print functions are
pure vitual. What if the print functions differed in the number of
parameters? For instance, assume the print methods for square and
triangle took 1 and 2 arguments respectively.

void print( int idx ) {} // square
void print ( int idx, int jdx ) // triangle..

Apr 3 '06 #1
5 1675
I V
ma740988 wrote:
Now the factory appears to be ideal considering the print functions are
pure vitual. What if the print functions differed in the number of
parameters? For instance, assume the print methods for square and
triangle took 1 and 2 arguments respectively.

void print( int idx ) {} // square
void print ( int idx, int jdx ) // triangle.. From the point of view of the factory, I don't think this would make a

difference. The problem is, what do you do with the objects created by
the factory if they don't have a common interface? You could use
dynamic_cast, as long as Shape has one or more virtual functions:

Shape* shape = Factory::make<Shape>("triangle");
Triange* triangle = dynamic_cast<Triangle*>(shape);
if( !triangle ) {
std::cerr << "I thought this was a Triangle, but it's not" <<
std::endl;
std::exit(1);
}
triangle->print(2, 3);

However, dynamic_cast is generally considered to be a less than ideal
solution, for various reasons, for one, that it defers type checking
from compile time to run time, which may mean bugs go undetected. If
Square and Triangle don't have a common interface (as they won't, if
they only have a "print" method which takes a different number of
arguments), then you probably shouldn't use them in a factory of the
sort you have above - the factory claims to create objects supporting a
given interface, and if there is no appropriate common interface, the
factory cannot behave properly (note that if there is no common
interface which Triangle and Square share, there shouldn't be a common
base type that they both derive from).

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.

Apr 3 '06 #2
If some interfaces are common, and other are common in functionality
(print) and not in prototype (different number of arguments) you may
use a function object for print, base class for the function object
will be the same (in the base class Shape) and the factory could create
the derived "Print" object.

Yuval.

Apr 3 '06 #3
You can define a more general API. If one of two prints takes one
argument and the other takes 2, then you can generalize the API of
print to take 2 arguments and you dont use the second argument in the
print that takes only one argument. As a result, the API fits both
prints.

A more gentle solution is define a parameter interface class and derive
2 subclasses from this interface.
Like:

class PrintParameter {
};

class OneArgumentPrintParameter {
int x;
};

class TwoArgumentPrintParameter {
int x;
int y;
};

then print methods look like ;

void print (PrintArgument *arg);

if this mehod is the one that needs one argument :

void print(PrintArgument *arg)
{
use ((OneArgumentPrintParameter *)arg)->x;
}

else

void print(PrintArgument *arg)
{
use TwoArgumentPrintParameter *)arg)->x;
use TwoArgumentPrintParameter *)arg)->y;
}
I hope it helps!

Apr 3 '06 #4
You can define a more general API. If one of two prints takes one
argument and the other takes 2, then you can generalize the API of
print to take 2 arguments and you dont use the second argument in the
print that takes only one argument. As a result, the API fits both
prints.

A more gentle solution is define a parameter interface class and derive
2 subclasses from this interface.
Like:

class PrintParameter {
};

class OneArgumentPrintParameter {
int x;
};

class TwoArgumentPrintParameter {
int x;
int y;
};

then print methods look like ;

void print (PrintArgument *arg);

if this mehod is the one that needs one argument :

void print(PrintArgument *arg)
{
use ((OneArgumentPrintParameter *)arg)->x;
}

else

void print(PrintArgument *arg)
{
use (TwoArgumentPrintParameter *)arg)->x;
use (TwoArgumentPrintParameter *)arg)->y;
}
I hope it helps!

Apr 3 '06 #5

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.

Apr 3 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

17
by: Medi Montaseri | last post by:
Hi, Given a collection of similar but not exact entities (or products) Toyota, Ford, Buick, etc; I am contemplating using the Abstraction pattern to provide a common interface to these products....
4
by: Eric | last post by:
Perhaps this question has been posed before (I'd be surprised if it hasn't) but I just gotta know... Is it possible to combine the Singleton and Factory Method design patterns in the same class?...
8
by: Craig Buchanan | last post by:
I've seen design patterns for class factories that work well to create (fetch) objects, but I haven't seen anything about how to persist the class' data when it has changed. Is this done thru the...
0
by: ma740988 | last post by:
I'm going through modern C++ design looking for tips and while hi-tech I suspect one solution to my issue would involve the factory design pattern. // algorithms.h class Algorithms {...
6
by: GarrettD78 | last post by:
Accidently posted this to the wrong group so I am reposting. This is probably a newbie question but I am a little confused about how to go next with my code. I think I want to use a factory pattern...
1
by: David Bellot | last post by:
Hi, if I consider the Factory Method design pattern, then I should have the following objects: Object and ObjectFactory which are usually abstract classes Then for each subclasses like...
10
by: sunny | last post by:
Does this following program implement the factory design.if not what are things that i have to change in order to make this following program to be designed to factory design pattern. ...
2
by: Duy Lam | last post by:
Hi everyone, Sorry, I don't know what group to post this problem, I think may be this group is suitable. I'm styduing DAO (Data Access Object) pattern in this link...
4
by: Pallav singh | last post by:
Hi , when should i select Factory Method / Prototype Design Pattern during my design phase ?? as both look similar to me Thanks in Advance Thanks Pallav
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.