tags:

views:

366

answers:

3

I don't know if there is an official name for this, but I have been playing with what I like to call the "self-factory" pattern. Basically, it's when an abstract base class acts as a factory for itself. Let me explain:

I have Foo objects and Bar objects in my system, which are used via interfaces FooInterface and BarInterface. I need to give my clients the right type of Foo and Bar. The decision of which concrete Foo object to create is made at compile time. For example, if you compile on win32, you want to only create Win32Foo objects, and if you compile on OSX you want to only create OSXFoo objects and so on. But, the decision of which concrete Bar object to create is made at runtime, based on a key string.

Now, my question is about the best way to implement this scheme. One way I come up with uses regular factories:

shared_ptr<FooInterface> foo = FooFactory::create();
shared_ptr<BarInterface> happyBar = BarFactory::create("Happy");
shared_ptr<BarInterface> sadBar = BarFactory::create("Sad");

Another way is to use what I call "self-factories":

shared_ptr<FooInterface> foo = FooInterface::create();
shared_ptr<BarInterface> happyBar = BarInterface::create("Happy");
shared_ptr<BarInterface> sadBar = BarInterface::create("Sad");

What are the pros and cons of each approach, both from a usability standpoint and from an architectural standpoint?

+1  A: 

Usually factories are responsible for creating objects of entire class hierarchies. So in your example you would have a Win32Factory, OSXFactory etc. One advantage of this is that you have to select the specific implementation ( win32/unix/etc) just once -- during factory creation, but if you use class interfaces, you have to supply the OS info all the time.

If you only have two classes (Foo and Bar) I'm not sure, if it's worth the effort to create factories for them and not just use a create method of the interfaces.

Oh, and when an interface has a method for creating objects of it's type, it's called the factory method pattern.

Kasprzol
+1  A: 

Factories have two common uses:

1) Decide dynamic polymorphic type at runtime, based on parameters and/or global state (such as configuration). Your pattern does this.

2) Dependency injection: rather than using a static function to create objects, use a factory object, so that the type of object returned can be configured by the caller, by passing in whatever factory they want. Neither of these patterns provides this. Furthermore, your second pattern doesn't even allow static dependency injection (by having template functions that take a factory class as a template parameter), because the interface and the factory are the same.

So one con of your pattern (and of your regular factories) is that dependency injection isn't really supported. There is one and only one function to call to get an object that's a FooInterface, and that is FooInterface::create(). I'll not argue why dependency injection is useful, just point out that if you build this way, you can't use it.

Steve Jessop
+1  A: 

I'd make an improvement:

shared_ptr<FooInterface> foo = Factory<FooInterface>::create();
shared_ptr<BarInterface> happyBar = Factory<BarInterface>::create("Happy");
shared_ptr<BarInterface> sadBar = Factory<BarInterface>::create("Sad");

You'd declare:

template <class I>
struct Factory { };

And then for each interface that needs a factory, you'd do this:

template <>
struct Factory<FooInterface>
{
    static FooInterface create();
};

This allows you to keep the factory implementation separate from the interface declaration, but still using the type system to bind them at compile time.

Daniel Earwicker