Archived

This topic is now archived and is closed to further replies.

stodge

Object factory question

Recommended Posts

stodge    144
This is a tough question to phrase for me, so bear with me. Is there a way to have classes automatically register themselves with an object factory at runtime? For example, I need an object factory that I can do: ObjectFactory::CreateObject("MyObject"); which will return an object of type MyObject. I''ve read the Reflective Factory resource on this site(hope that''s the name), but I don''t understand it no matter how hard I try. Also, it doesn''t appear to do the above, unless I''m mistaken in which case please tell me! So how could I code what I need? I presume I need objects to call a static function inside the object factory at runtime using some funky-code. The factory would contain an STL map that maps class naames to instances of objects. If you understood that, then thanks. If you can help, thanks again!

Share this post


Link to post
Share on other sites
Alan Kemp    772
I would do something like this:


  
typedef Object * (*CreationFunction)();

// The ObjectFactory class

// This has to be implemented as a singleton for this to work

class ObjectFactory
{
map < string, CreationFunction > ObjectMap;

static ObjectFactory & GetInstance()
{
static ObjectFactory factory;
return factory;
}

bool RegisterObject(string name, CreationFunction cf)
{
ObjectMap[name] = cf;
return true;
}

Object * CreateObject(string name)
{
CreationFunction cf = ObjectMap[name];
Object * obj = cf();
// not sure if this is syntax correct

// basically, call the function pointer that is stored

// in the map against the key "name"

return obj;
}
};

// Now each object is declared:

// ShinyObject.h

class ShinyObject : public Object
{
// some functions

};

// ShinyObject.cpp


// You need to declare the creation function

Object * ShinyObjectCreationFunction()
{
return new ShinyObject;
}

// You also define a function

bool RegisterShinyObject()
{
return ObjectFactory::GetInstance().RegisterObject("ShinyObject", ShinyObjectCreationFunction);
}

// Now for the real magic :-)

// Because its static const it will get automagically called *before* main starts

static const bool ShinyObjectRegistered = RegisterShinyObject();



Hope that helps,

Alan

Share this post


Link to post
Share on other sites
Sneftel    1788
Yes, there is a way. Search for "pluggable factory pattern"; the first link on google is a good one.


Don''t listen to me. I''ve had too much coffee.

Share this post


Link to post
Share on other sites
bslayerw    122
You could also use the prototype pattern in conjunction with the factory pattern.

example:

    
//all objects that are created should sub-class this.

class MyObject {

public:
virtual MyObject * clone() { return new MyObject(); }
virtual ~MyObject(){}
};

class Example: public MyObject {

public:
virtual MyObject * clone() { return new Example(); }
};


Then you simple register the prototype with the factory :


MyObject * protoype = new Example();
ObjectFactory::GetInstance().RegisterObject("ShinyObject", protoype );

//you can create instances like this:


MyObject* ObjectFactory::create(string const & objName) {
map < string, MyObject* >::const_iterator it = objectMap.find(objName);
if(it != objectMap.end()) {
return (it->second)->clone();
}
else
return static_cast<MyObject*>(NULL);

}


[edited by - bslayerw on January 29, 2003 1:16:56 PM]

Share this post


Link to post
Share on other sites
SabreMan    504
quote:
Original post by stodge
This is a tough question to phrase for me, so bear with me. Is there a way to have classes automatically register themselves with an object factory at runtime?

No. There are all manner of hacks which allow you to pretend that you can do this, and none of them are actually "automatic registration". Of course, the word "hack" has an image problem, and has recently had a makeover to become "pattern". When you can''t do something in a language, you have to obscure the fact you can''t do it by spending hours writing oodles of code, by the end of which you''ve forgotten what you were actually trying to do, but had so much fun in the process that you''re going to make use of the end result anyway. The results of such activity have become known as "design patterns", and others have pointed you towards the particular pattern "pretend to automatically register a class, conveniently ignoring the bits that you have to write manually". Err... or is it called something else, I can''t quite remember...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by SabreMan
[quote]No. There are all manner of hacks which allow you to pretend that you can do this, and none of them are actually "automatic registration". Of course, the word "hack" has an image problem, and has recently had a makeover to become "pattern". When you can''t do something in a language, you have to obscure the fact you can''t do it by spending hours writing oodles of code, by the end of which you''ve forgotten what you were actually trying to do, but had so much fun in the process that you''re going to make use of the end result anyway. The results of such activity have become known as "design patterns", and others have pointed you towards the particular pattern "pretend to automatically register a class, conveniently ignoring the bits that you have to write manually". Err... or is it called something else, I can''t quite remember...


while i see your point i have to say that this argument can be applied to almost everything when you want.

Share this post


Link to post
Share on other sites
Alan Kemp    772
The point isn''t that it

quote:

"pretend[s] to automatically register a class, conveniently ignoring the bits that you have to write manually"



Yes, you do have to write your own creation/registration functions for each object, the point is that the ObjectFactory class has absolutly no knowledge of what objects are/are not available, so adding a new object just means creating its class, writing a creation/registration function and then starting to use it.

quote:

When you can''t do something in a language, you have to obscure the fact you can''t do it by spending hours writing oodles of code, by the end of which you''ve forgotten what you were actually trying to do, but had so much fun in the process that you''re going to make use of the end result anyway.



*Sigh*. If only everything were as nice as lisp :-)

Alan

Share this post


Link to post
Share on other sites
bslayerw    122
SabreMan,

I don''t think you know what the hell you are talking about. How exactly do you consider design patterns a hack?? I would frankly be very scared to see a large scale project that you have worked one (if any).

Also, design patterns are not the be all end all solution to everything. They are simple a guideline and an easy way to communicate an idea if you know what design patterns are.

[qoute]When you can''t do something in a language, you have to obscure the fact you can''t do it by spending hours writing oodles of code

This is C++, you can pretty much do anything with the language! Writing oodles of code?? I''d rather write a strong framework up front than spend the rest of my life undoing what I had done if I did not have some sort of design to start of with (something that design patterns afford us).

the VTable is a beautiful thing. Learn to use it.

Share this post


Link to post
Share on other sites
Seriema    634
what about the object "registering" in the constructor?

There are several ways to handle it from there.
¤ If it''s the first one (the object checks himself) then it registers, this could be used with a class counter.
¤ It always registers but the factory checks to see if it''s already registered
etc...

did that help?

"No lies of sugar can sweeten the sournes of reality"

}+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

Share this post


Link to post
Share on other sites
DeltaVee    138
I usually have a special constructor for each object where the parameter is a reference to the factory itself. In the base class of the object I register my self with the factory.

At the beginning of the program I just have a function that locally instantiates each and every object used in the program.

This is ok if the program in question is a ''server'' because it wont be restarted hundreds of times a day, so a long initialisation doesn''t usually worry me.

Share this post


Link to post
Share on other sites
SabreMan    504
quote:
Original post by bslayerw
I don't think you know what the hell you are talking about.

Fortunately, what you think is ultimately inconsequential.
quote:

How exactly do you consider design patterns a hack?

The GoF variety of design patterns demonstrate ways in which we can combine features in a language to create a verbose expression of a concept which is not expressible at a primitive level. In other words, they are descriptions of how to hack a feature into a language lacking that feature.
quote:

? I would frankly be very scared to see a large scale project that you have worked one (if any).

Why?
quote:

Also, design patterns are not the be all end all solution to everything. They are simple a guideline and an easy way to communicate an idea if you know what design patterns are.

I didn't say anything to the opposite of that effect. You're getting carried away. Are you on the design patterns defence team?
quote:

This is C++, you can pretty much do anything with the language!

Now, *that's* funny! Here's one thing you can't do: you can't have classes automatically register themselves with a factory.
quote:

Writing oodles of code?? I'd rather write a strong framework up front

Up front of what? Up front of knowing what you need? Then you must waste hours of time. I hope it's your own time you're wasting, I'd hate to think someone actually pays you to sit around pulling requirements out of thin-air and then coding 'em up.
quote:

than spend the rest of my life undoing what I had done if I did not have some sort of design to start of with

You've presented a false dilemma: there are more options than writing a framework up front or spending all your time tearing up and starting again.
quote:

(something that design patterns afford us).

What? Design patterns provide you with prescience?
quote:

the VTable is a beautiful thing. Learn to use it.

You don't *use* vtables in C++. You use dynamic despatch, which may or may not use vtables under the hood. Dynamic despatch is a minor concession to a world of polymorphism in a language which enforces non-polymorphism as the default.
quote:
Seriema
what about the object "registering" in the constructor?

Yes you can do that, but you would need to create a constructor which only executes on a per-class basis. One way of doing that is to create a static instance of the class which calls a special constructor to handle registration. Something like...


        
class Reg {}; // creates a unique type to overload on

class C
{
static const C register_me;
C(const Reg&)
{
std::cout << "Registered\n";
}
public:
C()
{}
};
const C C::register_me = Reg();


That ensures the constructor runs during program start-up, but leaves various problems:

- Static initialisation order is indeterminate, so if you have interdependent objects, you need to resolve this;
- What types should the factory create? If it is to exhibit polymorphic creation (i.e. "virtual construction"), then you need some extra trickery.

The first point can be resolved by ensuring the factory is a singleton, and thus gets instantiated by the first class wishing to register itself. The second point is more difficult, as it has implications throughout your application design. If you want polymorphic creation, then the C++ way of having a single factory create different types is to relate the types using public inheritance, and then to store pointers to the base. Note here, that you actually have to store an instance rather than some sort of class object, which is a terrible shortcoming of C++. This then shifts the problem from the factory to the stored classes. How do you create an instance given another instance? That's where the prototype pattern comes in.

Reviewing what you actually have to do, you need to invade your class with three things: a possibly artificial inheritance hierarchy, a "static constructor" to handle registration and a "prototype constructor" to handle creation. Nice, huh?

Given a sane language which doesn't throw away all useful information at compile-time, you can do all this off-the-bat. For example, in Lisp, you can do this:


   
(defclass base ()
())
(defclass derived1 (base)
())
(defclass derived2 (base)
())

(defun instance-from-string (string)
(make-instance (find-class (read-from-string string))))

That last line defines a function to create instances given a string naming the class of the instance. First, it generates a symbol from the string, then it uses find-class to see if there is a class corresponding to the symbol. If so, the class instance is returned and passed to make-instance. So, you have a so-called "class factory" in a single line of code, without any explicit registration or messy invasion of your classes. In this example, I've related derived1 and derived2 to base via inheritance. In reality, there's absolutely no requirement to do that to make the class factory work, since Lisp does not enforce non-polymorphism as the default. This is a good example of how C++ makes simple tasks tediously long-winded and tricky to get right.

What was that which just flew out the window? Oh it's OK, it was only abstraction... GoF design patterns my ass! Design patterns are a way of turning oneself into a human HLL compiler, so that we can kid ourselves we still have abstraction.

Edit: f'in formatting filters!

[edited by - SabreMan on January 30, 2003 8:05:53 AM]

Share this post


Link to post
Share on other sites
bslayerw    122
SabreMan,

I am a little confused at your response. You call Design Patterns a hack then you actually recommend them (the prototype and singleton)?

Then you take a quote out of context, obviously you don''t use the VTable directly!

I suppose linked lists must be a hack too? since they combine features of the language to create a verbose expression of a concept of a list? Which is not expressible at a primitive level. Strings must be a hack too. Pretty much goes for most data structures.

Do you have any other suggestions on how to solve a problem besides giving examples in Lisp? I don''t know anything about Lisp but does it support the composite and visitor pattern as a feature? Two patterns that are extremely helpful regardless of language.


Share this post


Link to post
Share on other sites
SabreMan    504
quote:
Original post by bslayerw
I am a little confused at your response. You call Design Patterns a hack then you actually recommend them (the prototype and singleton)?

You can remove your confusion by realising that I've never said hacks aren't necessary.
quote:

I suppose linked lists must be a hack too?

Linked lists aren't design patterns. Don't try and disprove via false analogy.

[edited by - SabreMan on January 31, 2003 6:27:04 AM]

Share this post


Link to post
Share on other sites
bslayerw    122
Actually,

It could be argued that the concept of a linked lists could very well be a design pattern. Just because it's not in the GOF book does not mean it's not a design pattern. Don't be blinded by the term, design patterns have been around long before the words, "Design Patterns".

[edited by - bslayerw on February 2, 2003 9:33:08 PM]

Share this post


Link to post
Share on other sites
Arild Fines    968
The GoF book defines its collection of patterns as "descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context." I''d say it would be quite possible to describe a linked list in those terms.
Defining patterns as mere hacks and workarounds for language deficiencies, especially in the context of that definition, seems a bit narrow-minded, IMNSHO.



"I know very well who Satan is: He is freedom. He is the uncontrolled, the incalculable, the antithesis of order and discipline, the antithesis of the legalism of outer space.... We know where a planet will be in twelve years, four months and nine days. But we don''t know where a butterfly will have flown one minute hence. Therefore the butterfly is of Satan."
-- Jens Bjørneboe

Share this post


Link to post
Share on other sites
Arild Fines    968
quote:
Original post by bslayerw
Do you have any other suggestions on how to solve a problem besides giving examples in Lisp? I don''t know anything about Lisp but does it support the composite and visitor pattern as a feature? Two patterns that are extremely helpful regardless of language.


CLOS supports multiple dispatch, ie virtual calls that depends on the dynamic type of more than one object. This lessens or eliminates the need for visitors. The implementation section of the GoF description of visitor discusses this.



"I know very well who Satan is: He is freedom. He is the uncontrolled, the incalculable, the antithesis of order and discipline, the antithesis of the legalism of outer space.... We know where a planet will be in twelve years, four months and nine days. But we don''t know where a butterfly will have flown one minute hence. Therefore the butterfly is of Satan."
-- Jens Bjørneboe

Share this post


Link to post
Share on other sites
SabreMan    504
quote:
Original post by bslayerw
It could be argued that the concept of a linked lists could very well be a design pattern.

Hmmm....
quote:

Just because it''s not in the GOF book does not mean it''s not a design pattern.

Actually, the patterns in the GoF book aren''t really patterns, as in the Alexandrian notion of the concept. This is well understood in the patterns community. For an interesting discussion on the issues, check out this Usenet thread. Note in particular, Richard Gabriel''s comments, such as Message #4. Richard is one of the leaders of the patterns community.

Share this post


Link to post
Share on other sites
SabreMan    504
quote:
Original post by Arild Fines
Defining patterns as mere hacks and workarounds for language deficiencies, especially in the context of that definition, seems a bit narrow-minded, IMNSHO.

The problem with GoF''s design patterns isn''t so much the things in themselves, but the perception of what they are. Many people have a hugely over-inflated impression of GoF, and my comments are a general counter-reaction. In a wider context, 16 of the 23 patterns in GoF have been identified as static language workarounds, which serves as a highly effective counterpoint to the view that GoF''s patterns are language agnostic. Quite simply, GoF''s patterns aren''t "patterns" in the Alexandrian sense (which is the only sense that I''m willing to accept), and I''ve heard it said that even the authors now freely admit that (would be nice if I had a link). I have no problem with them being regarded as language-specific idioms, which helps dress-down the "silver bullet" appeal that some people attach to GoF.

Share this post


Link to post
Share on other sites
davepermen    1047
order-dependent initialisation isn''t much of a problem.. it never was.. but it doesn''t mather.. sabreman flooded this topic..

and it would be offtopic anyways..

its shown how to do, its rather simple, and not hackish at all..

your lisp example is simply bullshit, because all it shows is wow, you can use classnames directly to create classes. thats what c++ doesn''t provide => you have to do it yourself. if lisp wouldn''t support this, you would be in the need of setting up something similar. now you can come and say that should be supported by c++. that is your opinion. my one is different.

"take a look around" - limp bizkit
www.google.com

Share this post


Link to post
Share on other sites
SabreMan    504
quote:
Original post by davepermen
your lisp example is simply bullshit, because all it shows is wow, you can use classnames directly to create classes.

Which is exactly what the OP asked about.
quote:

now you can come and say that should be supported by c++.

I wasn''t commenting on whether or not C++ should support it, I was pointing out that it doesn''t support it and, therefore, the answer to the OP''s question in absolute terms is "no". Many people ask this same question about C++, particularly those coming from environments which allow runtime evaluation of expressions, so it is worth pointing out that this is something C++ cannot do.

Share this post


Link to post
Share on other sites