views:

124

answers:

5

This has bothered me for awhile, and I have no clues if this is a myth.

It seems that a factory pattern can ease the pain of adding a dependency for a class.

For example, in a book, it has something like this

Suppose that you have a class named Order. Initially it did not depend on anything. Therefore you didn't bother using a factory to create Order objects and you just used plain new to instantiate the objects. However, you now have a requirement that Order has to be created in association with a Customer. There are million places you need to change to add this extra parameter. If only you had defined a factory for the Order class, you would have met the new requirement without the same pain.

How is this not same pain as adding an extra parameter to the constructor? I mean you would still need to provide an extra argument for the factory and that is also used by million places, right?

A: 

You tell the factory about the new dependency, and let it add it for you. The method call to the factory should be unchanged.

David M
If I need to tell the factory about the new dependency, then how is this different from using plain old "new" and adding an extra argument? The new dependency is not a fixed object.
leiz
You tell the factory once, not everywhere in the code where you call the factory to create the object.
David M
+1  A: 

No, because the dependency for the factory should be injected via the factories constructor, and you are only constructing the factory in one place, but the passing it as the dependency to everything that needs to create an order. The things which are getting orders from the factory are still calling the same method, CreateOrder() or whatever, and so that code is unchanged.

The dependencies should all be wired up in a single place, the composition root, and that should be the only place that needs to change, to add the new dependency to the factory

Sam Holder
I don't quite get it. Say I want to create an Order object, it depends on a customer object, but the customer is known only at the time creating Order object. How am I suppose to setup factory at early stage?
leiz
This is not adding a dependency to the class though, is it? this is adding new information. If you need new information to be able to create your order then you are going to need to add that everywhere. But if you can determine the customer from the existing information, if say the Order class had access to an ICustomerResolver implementation, then if you had used a factory you could inject the ICustomerResolver into the factory and your Order creation code would remain unchanged. Without the factory you would need to inject the ICustomerResolver into every Order constructor.
Sam Holder
I am sorry, but I thought a new information was a dependency. And all the designs had to already know there would be a new customer requirement. That is why I am saying the book is misleading.
leiz
A: 

Factories are typically objects with state, and they typically have a single function to instantiate an instance; any parameters would would be given to the constructor of the object being instantiated are provided to the constructor of the factory object or are known to the factory object in some other way. Thus, you would not need to pass any additional information to the factory; you would invoke the factory's instantiation function, and you would only have to modify the factory that got constructed to use the other constructor.

To make this more concrete, you might have something like this:

template<typename T> class Factory
{
    public:
        virtual T* instantiate()const=0;
};

// One possible implementation
class MyClassFactory1 : public Factory<MyClass>
{
      public:
          virtual T* instantiate()const { return new MyClass; }
};

// Another possible implementation
class MyClassFactory2 : public Factory<MyClass>
{
      public:
          MyClassFactory(ParamType1 p1, ParamType p2) : p1(p1), p2(p2) {}
          virtual T* instantiate()const { return new MyClass(p1,p2); }
      private:
          ParamType1 p1;
          ParamType2 p2;
};

// Code that uses it:
void blah(const Factory<MyClass>& f)
{
     // ...
     MyClass* x = f.instantiate(); // <= this line never needs to change
     // ...
}
Michael Aaron Safyan
Thanks for the code. But, to create MyClassFactory2, I need to provide p1 and p2. If p1 and p2 are known only at the time when I need to create MyClass, how is different from inserting an extra to the constructor?
leiz
@leiz, if the parameters are an external dependency, then whatever provides that external dependency should also be able to provide the factory object. If not, then you right, it doesn't help.
Michael Aaron Safyan
+3  A: 

The real benefit to using a Factory is that it is a façade which hides just how you go about creating an object that fulfills the Order role. To be more exact, the Factory knows that you're really making a FooBarOrder, and nothing else has to be changed to switch from always making a FooBarOrder to sometimes making a BarFooOrder instead. (If Java let you intercept new and make a subclass instead, there would be no need for Factories. But it doesn't – fairly reasonably, to be fair – so you have to have them. Object systems which allow subclassing the class of classes are more flexible in this regard.)

Donal Fellows
That is how I understand the factory pattern too. But people just keep saying it is also helpful in the case of adding dependency, and that is something I don't get.
leiz
You had originally an Order, created by your factory, implementing IOrder. Now you want to have a CustomerOrder. Assuming that all the information required to create a CustomerOrder is available in the same information needed to create an Order, or can be determined from that information or statically, then the factory can now return a CustomerOrder without any changes to the code. If the factory needs a new dependency to help it get the CustomerObject needed to create the CustomerOrder then that change only need to happen to the factory, not to every place you create an Order.
Sam Holder
+3  A: 

If the user is known only at the time, the order is created, you could implement a getCurrentUser() function that is called by the factory.
If that is possible, the factory function obviously wins. If not, then there is no gain.

If, in the past, you didn't know there would ba a customer needed, you probably also could not know whether it's possible to implement a getCurrentUser() function. The chances of the factory method paying off may not be very good but they don't always equal 0.

mxp
I think it is exactly what I am looking for.
leiz
exactly. if you need new information your factory is not going to help. if you have, or can get, the information you need then the factory helps avoid the changes everywhere.
Sam Holder