universal factory

4 views
Skip to first unread message

Bronek Kozicki

unread,
Sep 3, 2003, 3:13:59 AM9/3/03
to
We (readers of this newsgroup) are already used to questions similar to:
"how can I write a function/class which will be able to create objects
of any class, given it's identifier in runtime" . Usual answer to such
question is "check factory pattern", with more or less details. More
general answer is "check creational patterns in GoF". There are few
creatinal patterns, all of them have some limitations, though. Abstract
Factory can be used to create families of classes, where each object
must belong to one of these (predefined) families, ie. must derrive from
one of predefined parent classes. Factory is even simpler and can be
used to create objects of set of classes derived from one, predefined
class. Anderi Alexandrescu in MC++D has implemented both patterns using
power of generic programming to allow easy creation of factory from
template. Still, there's no way to create single factory able to create
objects of any class - you must create different factories for different
sets of classes. There is also Prototype pattern, but it also has some
limitations.

I believe that there is a way to create "universal factory", ie. single
factory (single class, possibly monostate or singleton) able to create
objects of any polymorphic class (having virtual destructor, but not
limited in any other way, especially to predefined set of base classes),
but before I describe my idea, I want to ask you simple question: how
would you use such a factory? Would it be really usefull ?

waiting for your responses,


B.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Attila Feher

unread,
Sep 3, 2003, 11:33:23 AM9/3/03
to
Bronek Kozicki wrote:
[SNIP]

> I believe that there is a way to create "universal factory", ie.
> single factory (single class, possibly monostate or singleton) able
> to create objects of any polymorphic class (having virtual
> destructor, but not limited in any other way, especially to
> predefined set of base classes), but before I describe my idea, I
> want to ask you simple question: how would you use such a factory?
> Would it be really usefull ?

Of course it can be done, inherit everything from CObject (having a virtual
destructor and possibly a pure virtual clone member). But how would you use
that? You ask the factory for a class X. You get it. What would you do
with it? All you have is the "rich" interface of CObject: nothing. So you
will need to cast to to some sort of "interface class" (a polymorph base
class of some class hierarchy, like Shape) to be able to do anything with
it. So IMHO while it can be done it makes absolutely no sense.

It might be possible to create one factory template and allow the user of
that template to create specializations for different families. So you
could say "I want a shape which is called circle":

Shape *p = factory.create<Shape>( "Circle");

The question is: is it worth the trouble? One would need to look deeply
into this and see if it is possible to create such a "main factory". If it
is, it might make a lot of sense to standardize it, so people could just
extend this main factory template and use it everywhere.

--
Attila aka WW

Bronek Kozicki

unread,
Sep 3, 2003, 5:47:20 PM9/3/03
to
On 3 Sep 2003 11:33:23 -0400, Attila Feher wrote:

> Bronek Kozicki wrote:
> [SNIP]
>> I believe that there is a way to create "universal factory", ie.
>> single factory (single class, possibly monostate or singleton) able
>> to create objects of any polymorphic class (having virtual
>> destructor, but not limited in any other way, especially to

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


>> predefined set of base classes),

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> Of course it can be done, inherit everything from CObject (having a virtual
> destructor and possibly a pure virtual clone member).

I think you missunderstood me.

> It might be possible to create one factory template and allow the user of
> that template to create specializations for different families. So you
> could say "I want a shape which is called circle":

Andrei Alexandrescu already wrote such factory, and I see no point
improving it. Please, read my post again. I will soon desribe my idea in
more detail, here is sample usage:

// translation unit A
// header interfaces.h
class Shape {virtual ~Shape() /*...*/};
class Canvas {virtual ~Canvas() /*...*/};

class Circle : public Shape {/*...*/};
class Printer : public Canvas {/*...*/};

factory::register_class<Circle>("circle");
factory::register_class<Printer>("printer");
// actually, function register_class gets class identifier (like
// "circle" or "printer") from somewhere else, it's not a parameter

// translation unit B
class Shape {virtual ~Shape() /*...*/};
class Canvas {virtual ~Canvas() /*...*/};

std::auto_ptr<Shape> circle;
if (factory::create("circle", circle))
{
// fine, we have some circle
}
std::auto_ptr<Canvas> printer;
if (factory::create("printer", printer))
{
// great, we have a printer
}

I believe, that such factory is perfectly doable, but before I go into
futher details, I'd love to hear your opinions: would it be useful ?


B.

Aaron Bentley

unread,
Sep 4, 2003, 11:49:34 AM9/4/03
to
Bronek Kozicki wrote:

> On 3 Sep 2003 11:33:23 -0400, Attila Feher wrote:
>
>
>>Bronek Kozicki wrote:
>>[SNIP]
>>

>>>I believe that there is a way to create "universal factory", able


>>>to create objects of any polymorphic class

I don't think the "universal factory" aspect is especially compelling.
printer=factory<Canvas>::create("printer") will serve the same purposes
just as well.

You could "return" your objects by throwing them. That would allow you
to "return" any conceivable type (and base type wouldn't matter), but
it's a dark path.

Don't get me wrong though-- associating a type with a string is a neat
trick if you can do it. Generating an instance of the type and
associating *that* with a string isn't nearly as good (requires
Assignable types), and that's the Prototype pattern anyway.

For producing structures from input data, it could be handy. You should
probably provide for parameter objects, though.

Aaron

--
Aaron Bentley
www.aaronbentley.com

Attila Feher

unread,
Sep 4, 2003, 11:54:20 AM9/4/03
to
Bronek Kozicki wrote:
[SNIP]

>> It might be possible to create one factory template and allow the
>> user of that template to create specializations for different
>> families. So you could say "I want a shape which is called circle":
>
> Andrei Alexandrescu already wrote such factory, and I see no point
> improving it. Please, read my post again.
[SNIP]

> I believe, that such factory is perfectly doable, but before I go into
> futher details, I'd love to hear your opinions: would it be useful ?

Weeeeeee (steam-sirens) "Logic module failed! All hand on board! Abandon
ship!"

I think (as a standard element) it would be useful - as I have said before.
What I do not get: if Andrei has made it, why do you say "you believe it is
doable"? Do you want something else?

--
Attila aka WW

Richard Smith

unread,
Sep 5, 2003, 8:45:50 AM9/5/03
to
Bronek Kozicki wrote:

> On 3 Sep 2003 11:33:23 -0400, Attila Feher wrote:
>
> > Of course it can be done, inherit everything from CObject (having a virtual
> > destructor and possibly a pure virtual clone member).
>
> I think you missunderstood me.

I presume your trick is to inject an additional common base
class transparently to the end user. Something like the
following:

class factory : boost::noncopyable {
public:
template <class Product>
static bool register_class( std::string const& identifier ) {
instance().creators[identifier] = &create<Product>;
return true;
}

template <class ProductBase>
static bool create( std::string const& identifier,
std::auto_ptr<ProductBase>& dest ) {
create_map::const_iterator i
= instance().creators.find(identifier);
if ( i == instance().creators.end() ) return false;
std::auto_ptr<base> product( i->second() );
if ( ProductBase* b
= dynamic_cast<ProductBase*>( product.get() ) ) {
product.release(); dest.reset(b); return true;
}
return false;
}

private:
factory() {}
~factory() {}

static factory& instance() {
static factory instance; return instance;
}

class base { public: virtual ~base() {} };
typedef std::auto_ptr<base> (*create_function)();
typedef std::map< std::string, create_function > create_map;

template <class Product>
static std::auto_ptr<base> create() {
struct derived : public Product, public base {};
return std::auto_ptr<base>( new derived );
}

create_map creators;
};


> I believe, that such factory is perfectly doable,

I agree ;-)

> but before I go into
> futher details, I'd love to hear your opinions: would it be useful ?

Occasionally, yes, I think it could be useful. Though in
general, I think a less generic class with stronger
type-safety is more useful. For example, with separate
Factory Methods for the Shape and Canvas hierarchies as one
might see in an Abstract Factory, you could catch the
following at compile time:

std::auto_ptr<Canvas> canvas;
factory::create( "circle", canvas );

That's not to say that your "Univeral Factory" isn't useful;
just that it isn't the best choice in all situations.

--
Richard Smith

Bronek Kozicki

unread,
Sep 5, 2003, 9:28:59 AM9/5/03
to
On 4 Sep 2003 11:54:20 -0400, Attila Feher wrote:

> Weeeeeee (steam-sirens) "Logic module failed! All hand on board! Abandon
> ship!"

;) sorry for my poor English, you know - sitting here in Warsaw,
listening to Polish radio and/or watching Polish TV it's sometimes
difficult to spell correctly my thoughts in English ;) I will try harder
(TV off).

> I think (as a standard element) it would be useful - as I have said before.
> What I do not get: if Andrei has made it, why do you say "you believe it is
> doable"? Do you want something else?

Yessss. What Andrei provided is generic implementation of Factory patter
and Abstract Factory. Former one requires parameter being abstract (top)
class of your hierarchy, later one requires list of abstract classes on
top of your selected hierarchies. For each hierarchy you are going to
support you must create separate specialization of Factory template
and/or include it in type list being parameter of Abstract Factory
specialization. In both cases, it's not possible to:
* have single factory object supporting many disconnected class
hierarchies (whole idea of Abstract Factory is to support many related
hierarchies, but please note word "disconnected" I used here)
* add support for another class hierarchy to Abstract Factory not
recompiling it (actually all translation units which happen to use this
factory).

These limitaions are not specific to Andrei's implementation, this is
just how these design patterns work. I believe that most natural way
Factories are being used is to create separate factory for each
hierarchy or set of related hierarchies (Abstract Factory), and if you
wish to support many class hierarchies, you end up having many factories
in your program. Or you switch to Prototype pattern, which I won't
describe here :o) (Aaron Bentley wrote few words about it in this thread
already). Of course, one possible way is to derive all objects from
single class (I would call it "path of Java programmer or someone
exposed to dangers of MFC programming for much too long time"), but this
leads to one, big and ugly hierarchy (just like MFC). This is definitely
not what I was seeking for.

It was "holy Grall" (at least to me) to devise *single factory class*
(template class is "family of classes", not single class - this is not
what I was looking for) able to create objects of *any type*, not
limited to some hierarchy/ies predefined in factory
definition/specialization. I wanted something, that will allow
programmer to simply append to selected translatin unit (possibly
implementation file of selected user class, ie. "myclass.cpp") some very
simple code necessary to register class in the factory and that's all.
>From now on, this class can be created by factory and used in other
translation units. No recompilation is necessary, neither any changes to
user class. Other translation units (using this concrete class, as
created by factory) do not have to see this class definition (decoupling
- this is important point of Factory pattern), but only it's interface
(ie. abstract class it inherits from). I will put these expectations in
short list:
* there are no special requirements to user class being registered in
factory, besides one obvious : it's must be well behaving polymorphic
class (following LSP; virtual destructors from top of hierarchy). You do
not have to modify class in any way, assuming this requirement is
satisfied.
* to use any object created by factory, you do not have to see its class
definition - its interface (abstract class/es it inherits from) will
suffice.
* any code which happens to use this factory do not have to be
recompiled when you add support for another class to it. You simply
register another class in factory and that's it;
* there is just one factory class (possible monostate or singleton, but
can be more objects) in your program.

Currently available patterns do not satisfy all these requirements at
once. I think that I've developed solution which is really close to
"holly Grall" described above (it still has some shortcomings, but I
believe all of them can be accepted by most of users) . Read on my next
post in this thread :-)


B.

White Wolf

unread,
Sep 6, 2003, 5:03:01 AM9/6/03
to
Richard Smith wrote:
[SNIP]

> class factory : boost::noncopyable {
> public:
> template <class Product>
> static bool register_class( std::string const& identifier ) {
> instance().creators[identifier] = &create<Product>;

Ehem. This hides errors! Registering two different things with the same ID
will just blindly overwrite the old one... Not really practical in a real
life sized development. :-(

--
WW aka Attila

Bronek Kozicki

unread,
Sep 6, 2003, 5:08:49 AM9/6/03
to
On 5 Sep 2003 08:45:50 -0400, Richard Smith wrote:
> I presume your trick is to inject an additional common base
> class transparently to the end user. Something like the
> following:

exactly :->

> That's not to say that your "Univeral Factory" isn't useful;
> just that it isn't the best choice in all situations.

absolutly agree. I already have an idea how to pass parameters to
constructor through factory::create, but it won't offer static type
safety neither (another chance for runtime failure instead).

Anyway, I started this thread also for discussion - can this be really
useful ? How would you use such factory ? Could it have some (maybe
unexpected ?) advantages, when compared to classical patterns ?


B.

Bronek Kozicki

unread,
Sep 6, 2003, 8:31:06 AM9/6/03
to
Here's my idea:

First we define very simple class, which will be used as a "package" for
our objects:

class ibox
{
public:
virtual ~ibox() {}
};

Our factory will create objects inherited from two classes: "package"
presented above, and class we actually registered in registry.

template <typename T>
class box : public ibox, public T
{
public:
box() {}
template <typename T1>
box(T1 t1) : T(t1) {}
template <typename T1, typename T2>
box(T1 t1, T2 t2) : T(t1, t2) {}
// etc., up to some predefined limit
};

This "package" is probably the only shortcoming of proposed solution:
objects being created are not "exactly" what you are expecting; there's
4-bytes (on my machine) overhead of additional vtable (from ibox
abstract class) and (if we happen to add virtual functions to ibox, and
we will do it) there's possibility that functions in user class having
the same name will be hidden. Err... I think I used wrong word here :o)

Now, here's how we are going to create box<T> objects. Let's create
simple "worker" abstract class, which will be responsible for this task:

class iworker
{
public:
virtual ibox* create() const = 0;
virtual ~iworker() {}
}

Next we create very simple template, derived from iworker abstract
class. We are going to use covariant return type from virtual function
create:

template <typename T>
class worker : public iworker
{
public:
box<T>* create() const
{
return new box<T>();
}
};

If our class does not have default constructor (or we are simply not
going to use it), we may write specialization of template class
worker<T> function create, just before registering it:

template <> box<UserClass>* worker<UserClass>::create() const
{
return new box<UserClass>(20);
}

I have no reasonable solution on how to pass initialization parameters
from factory client to object being created. But I'm searching for it :)

I think that now things look pretty simple: you just create
worker<YourClass> object on heap, save its address in iworker*, and put
this pointer in some factory registry. Simplest way to write such
factory would be :

class factory
{
typedef std::map<std::string, iworker*> registry_type;
registry_type registry_;
public:
template <typename T>
void register(const std::string& name)
{
iworker* worker_ptr = new worker<T> ();
registry_.insert(std::make_pair(name, worker_ptr));
}
ibox* create(const std::string& name)
{
registry_type::const_iterator registry_iter = registry_.find(name);
if (registry_iter != registry_.end())
return registry_iter->second->create();
return NULL;
}
// ...

Now, there's a problem that result of our create function is not what we
are expecting. We must use dynamic_cast (actually cross-cast) to
supplied (by user) abstract class, from which our registered class
inherits. Lets' create another (templated) function for this task inside
our factory class:
// ...
template <typename A>
bool create(const std::string& name, A*& object)
{
registry_type::const_iterator registry_iter = registry_.find(name);
if (registry_iter == registry_.end())
return false;
ibox* ptr_box = registry_iter->second->create();
if (!ptr_box)
return false;
object = dynamic_cast<A*> (ptr_box);
if (object)
return true;
delete ptr_box;
return false;
}
};

User can use this factory in quite simple way:
1. register your class:
myFactory.register<Printer>("printer");

2. create objects
Canvas* printer = NULL;
if (myFactory.create("printer", printer))
{
// fine, we have a printer!
}

Above is just draft of solution. There is still problem with
performance: each "create" call involves binary search of registry_ data
structure. Let's replace this map with simple table (C table or
std::vector) and remember index, where appropriate worker object for
each concrete class has be saved inside this table; user will look for
this index only once, in another data structure std::map<std::string,
size_t> (we will call it indexes_). Another problem is class name: it
should be property of class, not property of worker object being
registered. This can be easily achieved, we just add static data member
to box<> class template:

template <typename T>
class box : public ibox, public T
{ /* ... */
static const char class_name_[];
// ...

Of course this value must be defined for each class being registered in
our factory. We add one line to his class implementation file, before
registering it in factory:

template<> const char box<Printer>::class_name_[] = "printer";

We also need to change factory::register to support this static data
member:

class factory
{ /* ... */
template <typename T>
void register()
{
iworker* worker_ptr = new worker<T> ();
registry_.push_back(worker_ptr);
size_t index = registry_.size() - 1;
indexes_.insert(std::make_pair(std::string(box<T>::class_name_),
index));
}
// ...

We can also remember this index as static property of box<T>, like
following:

template <typename T>
class box : public ibox, public T
{ /* ... */
static long class_index_[];
}

template <typename T> long box<T>::class_index_ = -1;

template <typename T>
void factory::register<T>()
{
// ...
box<T>::class_index_ = index;
}

This index can be also used to discover "real" type of object created by
factory in runtime, we just need to add simple virtual function to ibox
abstract class:

class ibox
{ /* ... */
virtual long class_index() const = 0;
virtual const char * class_name() const = 0;
};

template <typename T>
class box : public ibox, public T
{ /* .... */
long class_index() const
{
return class_index_;
}
const char* class_name() const
{
return class_name_;
}
};

.... and call it from our object (cross-casting it to ibox* first).

There is still a lot of space for improvements (like better interface of
factory class, management of lifetime of worker objects etc.), but I
hope everyone gets an idea. I've polished it a little and published at
http://b.kozicki.pl/cpp/T80.cpp , you are welcome to examine, modify and
use it. It's not finished yet, all comments are welcome :)

Torsten Robitzki

unread,
Sep 7, 2003, 11:14:47 AM9/7/03
to
Bronek Kozicki wrote:
<snip>

> I believe that there is a way to create "universal factory", ie. single
> factory (single class, possibly monostate or singleton) able to create
> objects of any polymorphic class (having virtual destructor, but not
> limited in any other way, especially to predefined set of base classes),
> but before I describe my idea, I want to ask you simple question: how
> would you use such a factory? Would it be really usefull ?
>
> waiting for your responses,

I agree that a "universal factory" is doable. In my toy project I'm
using a factory to create object of totally unrelated types out of a
stream. The public interface looks like this:

template<class Base>
class registry
{
public:
registry& register_subclass(const char* key,
Base*(*func)(ipc::reader&));

bool end_of_list() const { return true;}

Base* construct(const char* key, ipc::reader& r) const;

static registry& instance();
};

An example of how to register a class hierarchy:
static bool registered = registry<Base>::instance()
.register_subclass("A", create<A,Base>::func)
.register_subclass("B", create<B,Base>::func)
.end_of_list();

where create::func is a simple helper provided with the library. There
is no need for a static member variable for each base class.

The implementation is quit simple and contain less then 30 lines of
code. If you are interested, I could make the sources available.

regards
Torsten

Ron

unread,
Sep 9, 2003, 5:14:45 PM9/9/03
to
> The implementation is quit simple and contain less then 30 lines of
> code. If you are interested, I could make the sources available.

Yes, please.

Ben Liddicott

unread,
Sep 10, 2003, 4:02:15 AM9/10/03
to
Have you heard of COM?

--
Cheers,
Ben Liddicott

Torsten Robitzki

unread,
Sep 10, 2003, 4:10:56 AM9/10/03
to
Hi Ron ????,

Ron wrote:

>>The implementation is quit simple and contain less then 30 lines of
>>code. If you are interested, I could make the sources available.
>
>
> Yes, please.

http://www.robitzki.de/registry.h and http://www.robitzki.de/registry.cpp.

where dynmic_type is a wrapper around a pointer to type_info to serve as
a key into map.

regards
Torsten

Bronek Kozicki

unread,
Sep 10, 2003, 2:56:35 PM9/10/03
to
On 10 Sep 2003 04:02:15 -0400, Ben Liddicott wrote:

> Have you heard of COM?

I've been using it for few years already. It's binary interface. What
I'm talking about here, is at different level - ie. source code.


B.

Ben Liddicott

unread,
Sep 10, 2003, 7:33:32 PM9/10/03
to
You are simply re-inventing a less useful version of COM -- less useful because it only has source compatibility, instead of binary and source compatibility.

Use COM if it is available on your platform. If not, just re-implement the subset you need.
* Have some sort of registry of libraries and classes (config files?),
* Load the library which implements the named object and
* use a well-known entrypoint to return a singleton factory object.
* The factory object will give you as many instances as you like.
* Implement the above in a shared library which you can link to directly.
* Manage lifetimes with reference counting.
* Use smart pointers so you don't have to write lots of refcounting code.

In short, move along! Nothing to invent here.

--
Cheers,
Ben Liddicott

Aaron Bentley

unread,
Sep 13, 2003, 4:01:44 PM9/13/03
to
Here's what I came up with as a slightly-less-ambitious Universal
Factory, which I'm calling the Handy Factory for now. The "less
ambitious" bit is that it requires you to specify base class when
registering/constructing a class. (The advantage, though, is that a
class implementing several interfaces can participate in several
heirarchies.)

I haven't read Andrei's book, so I may be reinventing some wheels here.
It's prototype code (works on gcc 3.3.1), and I'd clean it up before
using. I think it's not hard to allow a single constructor parameter to
be used, and that parameter could be a tuple or struct (actually, any type).

Enjoy,

Aaron

--- example use ---
#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();
}
};

--
Aaron Bentley
www.aaronbentley.com

Reply all
Reply to author
Forward
0 new messages