Question

One of the ways to implement Dependency Injection correctly is to separate object creation from business logic. Typically, this involves using a Factory for object creation.

Up until this point, I've never seriously considered using a Factory so I apologize if this question seems a little simplistic:

In all the examples of the Factory Pattern that I've run across, I always see very simple examples that have no parameterization. For example, here's a Factory stolen from Misko Hevery's excellent How To Think About the "new" Operator article.

class ApplicationBuilder {
  House build() {
    return new House(new Kitchen(
               new Sink(),
               new Dishwasher(),
               new Refrigerator())
           );
  }
}

However, what happens if I want each house that I build to have a name? Am I still using the Factory pattern if I re-write this code as follows?

class ApplicationBuilder {
  House build( const std::string & house_name) {
    return new House( house_name,
                      new Kitchen(new Sink(),
                                  new Dishwasher(),
                                  new Refrigerator())
                    );
  }
}

Note that my Factory method call has changed from this:

ApplicationBuilder builder;
House * my_house = builder.build();

To this:

ApplicationBuilder builder;
House * my_house = builder.build("Michaels-Treehouse");

By the way: I think the concept of separating object instantiating from business logic is great, I'm just trying to figure out how I can apply it to my own situation. What confuses me is that all the examples I've seen of the Factory pattern never pass any parameters into the build() function.

To be clear: I don't know the name of the house until the moment before I need to instantiate it.

Was it helpful?

Solution

I've seen quite a lot of examples that use a fixed set of arguments, like in your name example, and have used them myself too and i can't see anything wrong with it.

However there is a good reason that many tutorials or small articles avoid showing factories that forward parameters to the constructed objects: It is practically impossible to forward arbitrary number of arguments (even for a sane limit like 6 arguments). Each parameter you forward has to be accepted as const T& and T& if you want to do it generic.

For more complicated examples, however, you need an exponentially growing set of overloads (for each parameter, a const and a nonconst version) and perfect forwarding is not possible at all (so that temporaries are forwarded as temporaries, for example). For the next C++ Standard that issue is solved:

class ApplicationBuilder {
  template<typename... T>
  House *build( T&&... t ) {
    return new House( std::forward<T>(t)...,
                      new Kitchen(new Sink(),
                                  new Dishwasher(),
                                  new Refrigerator())
                    );
  }
};

That way, you can call

builder.build("Hello", 13);

And it will return

new House("Hello", 13, new Kitchen(new Sink(...

Read the article i linked above.

OTHER TIPS

I can't see why it would be wrong to add this parameter to your factory. But be aware that you shouldn't end up adding many parameters which might not be useful to all objects created by the factory. If you do, you'll have lost quite a lot of the advantages of a factory !

Not only is is acceptable, but it's common to pass parameters to a factory method. Check out some examples. Normally the parameter is a type telling the factory what to make, but there's no reason you can't add other information you need to build an object. I think what you're doing is fine.

The idea of a factory is that it gives you an instance of a class/interface, so there is nothing wrong with passing parameters. If there were, it would be bad to pass parameters to a new() as well.

I agree with Benoit. Think of a factory for creating something like sql connections though, in a case like this it would be necessary to pass information about the connection to the factory. The factory will use that information to use the correct server protocol and so on.

Sure, why not..!?

The nice thing about passing parameters is that it allows you to hide the implementation of the concrete object. For example, in the code you posted you pass the parameters to the constructor. However, you may change the implementation so that they get passed via an Initiailze method. By passing parameters to the factory method you hide the nature of constructing and initializing the object from the caller.

Take a look at Loki::Factory, there's an implementation very much like it coming to Boost as well, however. Some example code i regularly use in different flavors:

typedef Loki::SingletonHolder< Loki::Factory< Component, std::string, Loki::Typelist< const DataCollection&, Loki::Typelist< Game*, Loki::NullType > > > > ComponentFactory;

This might seem a bit weird at first sight, however let me explain this beast and how powerful it really is. Basically we create a singleton which holds a factory, the out most parameters are for the singleton, Component is our product, std::string is our creation id type, after this follows a type list of the params which is required for creation of Components ( this can be defined using a macro as well for a less verbose syntax ). After this line one can just do:

ComponentFactory::Instance().CreateObject( "someStringAssociatedWithConcreteType", anDataCollection, aGamePointer );

To create objects, to register one just use ComponentFactory::Instance().Register();. There's a great chapter on the details in the book Modern C++ Design.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top