473,385 Members | 1,740 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,385 software developers and data experts.

Closing a factory method using dynamic object creation.

I've hit something of a snag.

Problem:

In a DSP application we have data profiles with a varying number of points.
We have a number of Discrete Fourier transforms that are optimised for a
specific number of points. Currently, any client of these DFT classes must
switch on the number of points in the profile and instanciate the correct
DFT algorithm.

switch( size )
case 2000:
return new DFT2000Point();
case 3600:
return new DFT3600Point();
// etc...

Clearly this is horse poo.

I've just created a factory class that takes a profile, and returns a base
class pointer to the correct concrete type of DFT. It does this currently by
again, switching on the number of points in the profile. Still not good, but
at least the clients are not having to replicate this code. The thing that
bothers me is that this method is not closed to change. Every time we add a
new DFT class, we have to modify this switch. Clearly I'd like to avoid
this.

So, how do I do it?

My first feeling is that their is an obvious mapping between the concrete
class, and the number of points. So I should perhaps have a map:

class DFTFactory
{
public:

Map<int size, const type_info &theType>;

// .....
With a create method:

auto_ptr<DFTBase> Create( int numberOfPoints )
{
//....
So my question is... how do I create an instance of a concrete class from
its type_info?
Cheers,

4Space
Jul 19 '05 #1
16 4318


4Space wrote:


I would do it this way:

You rmap is a good idea, so keep it, but instead of storing type_info's,
why not store pointers to already existing objects?

class DFTFactory
{
public:

void Register( int Size, DFTBase* pDFT );
DFTBase* LookUp( int Size );

private:
std::map< int, DFTBase* > m_TemplateObjects;
};

Now you derive all your DFT-Engines from a common DFTBase.
Every DFT-Engine creates at startup one instance and registers
that instance with the DFTFactory.
When the time has come to use a transformation object, the Factory
can look up one of those objects based on the requested size.
It then can either return a pointer to that object, or use a virtual
constructor idiom to create a copy from it, by calling the virtual
function Clone():

class DFTBase
{
public:
....
virtual DFTBase* Clone() = 0;
....
};

class DFT2000Point : public DFTBase
{
public:
....
virtual DFTBase* Clone() { return new DFTBase2000Point( *this ); };
....
};

When thinking of it, I believe that having only one DFT object around
(for each point size) should be sufficient, so you additionally might
investigate in exploring the Singleton pattern. But this is something
only you can decide.

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 19 '05 #2
> class DFTFactory
{
public:

void Register( int Size, DFTBase* pDFT );
DFTBase* LookUp( int Size );

private:
std::map< int, DFTBase* > m_TemplateObjects;
};

Now you derive all your DFT-Engines from a common DFTBase.
Every DFT-Engine creates at startup one instance and registers
that instance with the DFTFactory.


How should I tackle the registration? Use static initialisation in the
concrete class to instanciate itself and then register itself?

Cheers,

4Space

Jul 19 '05 #3


4Space wrote:
class DFTFactory
{
public:

void Register( int Size, DFTBase* pDFT );
DFTBase* LookUp( int Size );

private:
std::map< int, DFTBase* > m_TemplateObjects;
};

Now you derive all your DFT-Engines from a common DFTBase.
Every DFT-Engine creates at startup one instance and registers
that instance with the DFTFactory.


How should I tackle the registration? Use static initialisation in the
concrete class to instanciate itself and then register itself?

Cheers,


eg. a simple solution

int main()
{
DFT2000Points The2000PointDFT;
DFT2000Points The4000PointDFT;
DFTFactory TheDFTFactory;

TheDFTFactory.Register( 2000, &The2000PointDFT );
TheDFTFactory.Register( 4000, &The4000PointDFT );

...
}

or as you say: create a static instance and let it register
in the ctor

or ...

There are a number of possibilities

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 19 '05 #4
> eg. a simple solution

int main()
{
DFT2000Points The2000PointDFT;
DFT2000Points The4000PointDFT;
DFTFactory TheDFTFactory;

TheDFTFactory.Register( 2000, &The2000PointDFT );
TheDFTFactory.Register( 4000, &The4000PointDFT );

...
}
This just shuffles the problem to Main(), as it must be updated every time
we add a new concrete DFT.
or as you say: create a static instance and let it register
in the ctor
This sounds the way. I hadn't considered a combination of factory and
prototype.
or ...

There are a number of possibilities

Will investigate these also :¬) Many thanks for your input.
--
Karl Heinz Buchegger
kb******@gascad.at


Cheers,

4Space
Jul 19 '05 #5


4Space wrote:
class DFTFactory
{
public:

void Register( int Size, DFTBase* pDFT );
DFTBase* LookUp( int Size );

private:
std::map< int, DFTBase* > m_TemplateObjects;
};

Now you derive all your DFT-Engines from a common DFTBase.
Every DFT-Engine creates at startup one instance and registers
that instance with the DFTFactory.
How should I tackle the registration? Use static initialisation in the
concrete class to instanciate itself and then register itself?


A different concept which uses a creation function could look like this.
It has the advantage that each object is created only when needed. If your
DFT classes contain a substantial amount of members, then this would
be better.
#include <iostream>
#include <map>
using namespace std;

class DFTBase
{
public:
virtual void Use() { cout << "Error: can't use base class DFTBase\n"; }
};

/////////////////////////////////////////////////////////////
//
typedef DFTBase* (*CreateFnct)();

class DFTFactory
{
public:
void Register( int Size, CreateFnct pFunct )
{
m_Map[Size] = pFunct;
}

DFTBase* LookUp( int Size )
{
CreateFnct pFunc = m_Map[Size];
if( pFunc )
return pFunc();
return NULL;
}

protected:
std::map< int, CreateFnct > m_Map;
};

/////////////////////////////////////////////////////////////
//
class DFT2000 : public DFTBase
{
public:
static DFTBase* Create()
{
if( !m_p2000DFT ) {
cout << "2000 created\n";
m_p2000DFT = new DFT2000;
}
else
cout << "using existing 2000 engine\n";

return m_p2000DFT;
}

static void RegisterWith( DFTFactory& Factory )
{
Factory.Register( 2000, Create );
}

virtual void Use() { cout << "This is DFT for 2000 points\n"; }

private:
DFT2000() {}

static DFT2000* m_p2000DFT;
};

DFT2000* DFT2000::m_p2000DFT = 0;

/////////////////////////////////////////////////////////////
//
class DFT4000 : public DFTBase
{
public:
static DFTBase* Create()
{
if( !m_p4000DFT ) {
cout << "4000 created\n";
m_p4000DFT = new DFT4000;
}
else
cout << "using existing 4000 engine\n";

return m_p4000DFT;
}

static void RegisterWith( DFTFactory& Factory )
{
Factory.Register( 4000, Create );
}

virtual void Use() { cout << "This is DFT for 2000 points\n"; }

private:
DFT4000() {}

static DFT4000* m_p4000DFT;
};

DFT4000* DFT4000::m_p4000DFT = 0;

/////////////////////////////////////////////////////////////
//
int main()
{
DFTFactory Factory;

DFT2000::RegisterWith( Factory );
DFT4000::RegisterWith( Factory );

Factory.LookUp( 2000 )->Use();
Factory.LookUp( 4000 )->Use();
Factory.LookUp( 2000 )->Use();

return 0;
}
Cheers,

4Space


--
Karl Heinz Buchegger, GASCAD GmbH
Teichstrasse 2
A-4595 Waldneukirchen
Tel ++43/7258/7545-0 Fax ++43/7258/7545-99
email: kb******@gascad.at Web: www.gascad.com

Fuer sehr grosse Werte von 2 gilt: 2 + 2 = 5
Jul 19 '05 #6
Responding to 4Space...
I've hit something of a snag.

Problem:

In a DSP application we have data profiles with a varying number of points.
We have a number of Discrete Fourier transforms that are optimised for a
specific number of points. Currently, any client of these DFT classes must
switch on the number of points in the profile and instanciate the correct
DFT algorithm.

switch( size )
case 2000:
return new DFT2000Point();
case 3600:
return new DFT3600Point();
// etc...

Clearly this is horse poo.
Not necessarily. There is nothing inherently wrong with parameterizing
behavior with external data. The real issue is the level of abstraction
of the method containing the switch. If the fact that there are
multiple DFT packages is an implementation issue and not relevant to
problem being solved (e.g., one has chosen a third party DFT package
that has multiple entry points), then the dispatch is just part of the
the implementation of the responsibility to apply a DFT. In that case
it would probably be a bad idea to expose it beyond the client method.

OTOH, if the existence of multiple DFT algorithms is important to the
problem solution (e.g., the requirements specify the algorithm to use),
then one needs to expose that decision in the OOA/D. In fact, it is a
good idea to identify the decision as someone's unique, explicit
responsibility. The most straight forward way to do that is through
relationship instantiation:

0..* 1
[Client] ---------------------- [DFT]
A
|
+-------+-------+
| |
[2000DFT] [3600DFT]

Now someone decides which [DFT] subclass is appropriate for a particular
Client and instantiates the relationship to an instance of that
subclass. Then a Client simply addresses a message to whoever is at the
other end of the relationship (e.g., invokes the superclass method,
DFT->doIt() via a DFT* pointer).

Note that this is really just a simplified Strategy pattern. Whether
one needs the full decoupling of Strategy will depend on specific
context. It can be a simple as...

I've just created a factory class that takes a profile, and returns a base
class pointer to the correct concrete type of DFT. It does this currently by
again, switching on the number of points in the profile. Still not good, but
at least the clients are not having to replicate this code. The thing that
bothers me is that this method is not closed to change. Every time we add a
new DFT class, we have to modify this switch. Clearly I'd like to avoid
this.


....initializing a DFT* pointer in [Client]. IME, one would usually
initialize an instance of each DFT subclass at startup, probably by a
Factory. However, the size is likely to be dynamically defined at run
time. Whoever determines the size would need to instantiate the
relationship by setting the DFT reference attribute in the Client in hand.

So the only complication is mapping the size to a DFT instance (i.e.,
finding the right subclass instance to assign to the reference
attribute). How one does that will depend upon the context of when and
how the size is determined. One can have a static Find method in the
DFT class to look up the instance based on size; one can have the
decision maker do its own table lookup from a table that was initialized
as part of its construction; or any of several other variations. Either
way, a Factory will probably play a startup role in initializing a
lookup table somewhere.
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
hs*@pathfindersol.com
Pathfinder Solutions -- Put MDA to Work
http://www.pathfindersol.com
(888)-OOA-PATH


Jul 19 '05 #7
4S****@NoSpam.com (4Space) wrote (abridged):
or as you say: create a static instance and let it register
in the ctor


This sounds the way. I hadn't considered a combination of factory and
prototype.


Then you just have to ensure the file containing the class is linked into
the app. This can go wrong - some linkers will leave out an object file if
nothing it contains is needed by the main program, even if it contains
statics with constructors. Especially if the object file is in a library.
You may end up having to force the file to link in, which leads back to
the original problem :-)

-- Dave Harris, Nottingham, UK
Jul 19 '05 #8
In article <gE**********************@news.easynews.com>,
"4Space" <4S****@NoSpam.com> wrote:
switch( size )
case 2000:
return new DFT2000Point();
case 3600:
return new DFT3600Point();
// etc...

Clearly this is horse poo.
Yes, C++ *is* pretty crappy.
So, how do I do it?


Switch to a better implementation language. A solution in Objective-C
(using the OpenStep API):

sizedDFTClass = NSClassFromString([NSString stringWithFormat:
@"DFT%dPoint", size]);
Jul 19 '05 #9
Doc O'Leary wrote:
In article <gE**********************@news.easynews.com>,
"4Space" <4S****@NoSpam.com> wrote:

switch( size )
case 2000:
return new DFT2000Point();
case 3600:
return new DFT3600Point();
// etc...

Clearly this is horse poo.

Yes, C++ *is* pretty crappy.


Why do you feel it's necessary to post this in comp.lang.c++? Are you a
troll?

So, how do I do it?

Switch to a better implementation language. A solution in Objective-C
(using the OpenStep API):

sizedDFTClass = NSClassFromString([NSString stringWithFormat:
@"DFT%dPoint", size]);


Objective C is off-topic in comp.lang.c++. Please don't post such things
here.

-Kevin
--
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.

Jul 19 '05 #10
"4Space" <4S****@NoSpam.com> wrote in message news:<xA**********************@news.easynews.com>. ..
class DFTFactory
{
public:

void Register( int Size, DFTBase* pDFT );
DFTBase* LookUp( int Size );

private:
std::map< int, DFTBase* > m_TemplateObjects;
};

Now you derive all your DFT-Engines from a common DFTBase.
Every DFT-Engine creates at startup one instance and registers
that instance with the DFTFactory.


How should I tackle the registration? Use static initialisation in the
concrete class to instanciate itself and then register itself?


Make your Register return a bool. Give each derived class a static
Create fn that returns new <DerivedClass>. In the factory store a map
of fn's
Then, in the source file for every derived class, put something like
the following:

namespace
{
bool bRegistered = TheDFTFactory.Register( 2000,
The2000PointDFT::Create );
}

Eric Beyeler
Jul 19 '05 #11
In article <uJ*****************@newsread3.news.pas.earthlink. net>,
Kevin Goodsell <us*********************@neverbox.com> wrote:
Why do you feel it's necessary to post this in comp.lang.c++? Are you a
troll?
Welcome to Usenet, Freshman Goodsell. Educate yourself regarding cross
posts.
Objective C is off-topic in comp.lang.c++. Please don't post such things
here.


All OO topics are fair game in comp.object, though. I agree that the
OP's cross post was questionable, what with C++ being such a horrid OO
language with no real object support. Feel free to edit followups
(another thing that you probably need to learn about) if you're so
fragile that you cannot stand to hear about alternatives.
Jul 19 '05 #12
Doc O'Leary wrote:
In article <uJ*****************@newsread3.news.pas.earthlink. net>,
Kevin Goodsell <us*********************@neverbox.com> wrote:

Why do you feel it's necessary to post this in comp.lang.c++? Are you a
troll?

Welcome to Usenet, Freshman Goodsell. Educate yourself regarding cross
posts.


Hmmmm...

http://groups.google.com/groups?q=author:Doc%20author:O'Leary
Results 1 - 10 of about 2,090

http://groups.google.com/groups?q=au...uthor:goodsell
Results 1 - 10 of about 6,040

This "Freshman" has nearly 3 times as many posts as you. And I'm very
familiar with the cross-post, thank you very much. Please educate
yourself regarding netiquette.

(Granted, this doesn't actually prove anything since you could have
posted under a different name. Personally, I've never felt the need to
hide behind an alias on Usenet.)

Objective C is off-topic in comp.lang.c++. Please don't post such things
here.

All OO topics are fair game in comp.object, though.


Fine, but you also posted to comp.lang.c++.
I agree that the
OP's cross post was questionable,
I only take issue with your cross-posting an intentionally inflammatory
message here, when you could have simply removed comp.lang.c++ from the
crosspost list. Clearly your only reason for not doing so was to pick a
fight with this group.
what with C++ being such a horrid OO
language with no real object support.
And the trolling continues.
Feel free to edit followups
(another thing that you probably need to learn about)
Nope, I've got that down also.
if you're so
fragile that you cannot stand to hear about alternatives.


My interests in programming extend well beyond C++ already. The issue
here is your trolling, not my language preferences.

I've also mastered the killfile, fortunately.

-Kevin
--
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.

Jul 19 '05 #13
In article <xX***************@newsread4.news.pas.earthlink.ne t>,
Kevin Goodsell <us*********************@neverbox.com> wrote:
This "Freshman" has nearly 3 times as many posts as you. And I'm very
familiar with the cross-post, thank you very much. Please educate
yourself regarding netiquette.
Wow. You know, I was actually referring to your maturity level, and
your turning it into a pissing match supports my point in ways I never
imagined. Clearly you think quantity makes up for quality, and clearly
you think your search is representative, yet it shows no posts for you
prior to 1998 while my search goes all the way back to 1991. So maybe,
just maybe, you need to rethink your position as to who has the "junior"
position here. While you're at it, rethink your choice of language,
because C++ is still a terrible OO language.
(Granted, this doesn't actually prove anything since you could have
posted under a different name. Personally, I've never felt the need to
hide behind an alias on Usenet.)
Neither have I. But if you want to go full-blown ego surfing (and you
seem like the type that does), you'll find what I expect is my first
Usenet posting here:

http://groups.google.com/groups?q=au...n.edu&start=13
0&hl=en&as_drrb=b&as_mind=12&as_minm=5&as_miny=198 1&as_maxd=8&as_maxm=4&a
s_maxy=1992&selm=2605%40ux.acs.umn.edu&rnum=131
I only take issue with your cross-posting an intentionally inflammatory
message here, when you could have simply removed comp.lang.c++ from the
crosspost list. Clearly your only reason for not doing so was to pick a
fight with this group.
No, as it turns out I didn't care to read the Newsgroups line. I
thought the OP was asking about proper OO development, not hacking C++.
That is why I indicated that it was an odd sort of cross post to have.
I've also mastered the killfile, fortunately.


Excellent. Then I shall not be contributing to your future "quantity"
scores. You truly *are* the winner, Freshman Goodsell!
Jul 19 '05 #14
"4Space" <4S****@NoSpam.com> might (or might not) have written this on
(or about) Wed, 10 Sep 2003 12:14:22 GMT, :
class DFTFactory
{
public:

void Register( int Size, DFTBase* pDFT );
DFTBase* LookUp( int Size );

private:
std::map< int, DFTBase* > m_TemplateObjects;
};

Now you derive all your DFT-Engines from a common DFTBase.
Every DFT-Engine creates at startup one instance and registers
that instance with the DFTFactory.


How should I tackle the registration? Use static initialisation in the
concrete class to instanciate itself and then register itself?


Do the registration in 'main'.
Robert C. Martin | "Uncle Bob"
Object Mentor Inc.| unclebob @ objectmentor . com
PO Box 5757 | Tel: (800) 338-6716
565 Lakeview Pkwy | Fax: (847) 573-1658 | www.objectmentor.com
Suite 135 | | www.XProgramming.com
Vernon Hills, IL, | Training and Mentoring | www.junit.org
60061 | OO, XP, Java, C++, Python | http://fitnesse.org
Jul 19 '05 #15
"4Space" <4S****@NoSpam.com> might (or might not) have written this on
(or about) Wed, 10 Sep 2003 12:36:06 GMT, :
eg. a simple solution

int main()
{
DFT2000Points The2000PointDFT;
DFT2000Points The4000PointDFT;
DFTFactory TheDFTFactory;

TheDFTFactory.Register( 2000, &The2000PointDFT );
TheDFTFactory.Register( 4000, &The4000PointDFT );

...
}


This just shuffles the problem to Main(), as it must be updated every time
we add a new concrete DFT.


That doesn't bother me all that much. I often make 'main' (and its
cronies) the functions that aren't closed to modification.

If you absolutely *must* close main, then you can create one dll per
algorithm. Put all the necessary dlls in a directory. 'main' can
search the directory, load each dll, and using a standard function
call ask each one to register its algorithm.

Robert C. Martin | "Uncle Bob"
Object Mentor Inc.| unclebob @ objectmentor . com
PO Box 5757 | Tel: (800) 338-6716
565 Lakeview Pkwy | Fax: (847) 573-1658 | www.objectmentor.com
Suite 135 | | www.XProgramming.com
Vernon Hills, IL, | Training and Mentoring | www.junit.org
60061 | OO, XP, Java, C++, Python | http://fitnesse.org
Jul 19 '05 #16
> >How should I tackle the registration? Use static initialisation in the
concrete class to instanciate itself and then register itself?


Do the registration in 'main'.


Because we have an array of reusable components, we're very careful of what
we expose. There are many layers between the concrete algorithm and main. If
we adopted this approach, it would gimp the component's reusability. i.e. It
couldn't stand alone as a component, it would need all users of this
component to add code to initialise a low level component, a component that
they shouldn't really know exists.

Cheers,

4Space
Jul 19 '05 #17

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....
2
by: Ryan Mitchley | last post by:
Hi all I have code for an object factory, heavily based on an article by Jim Hyslop (although I've made minor modifications). The factory was working fine using g++, but since switching to the...
10
by: Chris Croughton | last post by:
What do people call their factory functions? 'new' is not an option (yes, it can be overloaded but has to return void*). The context is: class MyClass { public: // Factory functions...
1
by: Rajiv Das | last post by:
I have run into a design time problem and I look for help. This is the crux of the design. : class IShape{ public: virtual void Draw() = 0; }; class Circle : public IShape{
4
by: max | last post by:
Hello, I analyze this design pattern for a long time but I do not understand how this pattern work and what the purpose is? (I looked a this site...
10
by: Mark | last post by:
I have an abstract class, and a set of classes that inherit from my abstract class. The fact that it is abstract is likely irrelevant. I have a static factory method in my abstract class that...
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...
6
by: Nindi | last post by:
5 Files Singleton.h The Singleton Factory.h The factory creating new objects. The Base class of the hierachy stores a typelist identifying the signature of the constructors to be called...
2
by: r035198x | last post by:
Ok i've overdone something here. I thought I'd make a factory of singletons during lunch package factory; import java.util.*; class SingletonFactory { static Hashtable<Class, Boolean>...
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: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
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...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

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.