8

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?

Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308
leiz
  • 3,984
  • 2
  • 23
  • 17
  • There are millions (if not billions) of books out there. Not all of them are correct. Do not take anything for granted just because somebody wrote it in a book. – kazanaki Dec 17 '13 at 16:25

5 Answers5

5

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.

foraidt
  • 5,519
  • 5
  • 52
  • 80
  • 1
    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 Apr 23 '10 at 10:48
3

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
  • 133,037
  • 18
  • 149
  • 215
  • 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 Apr 23 '10 at 10:14
  • 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 Apr 23 '10 at 10:33
2

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

Community
  • 1
  • 1
Sam Holder
  • 32,535
  • 13
  • 101
  • 181
  • 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 Apr 23 '10 at 10:01
  • 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 Apr 23 '10 at 10:21
  • 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 Apr 23 '10 at 10:28
1

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
  • 71,481
  • 13
  • 158
  • 186
  • 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 Apr 23 '10 at 10:16
  • You tell the factory once, not everywhere in the code where you call the factory to create the object. – David M Apr 23 '10 at 12:11
1

The factory pattern can ease the pain of adding a dependency, because a factory may contain state and, in fact, can encapsulate multiple dependencies (e.g. instead of providing three dependencies, all needed to invoke some object's constructor, you now provide only a single factory object, where the factory contains those three objects that are needed to be provided to the constructor).

To give an example, compare:

void DoIt(const DependencyA& a, const DependencyB& b) {
   // NOTE: "x" is a contrived additional variable that we add here to
   // justify why we didn't just pass DependencyC directly.
   int x = ComputeX(); 
   std::unique_ptr<DependencyC> dependency_c(new DependencyC(a, b, x));
   dependency_c->DoStuff();
}

And:

void DoIt(const DependencyCFactory& factory) {
  int x = ComputeX();
  std::unique_ptr<DependencyC> dependency_c(factory->Create(x));
  dependency_c->DoStuff();
}

Note that the second version required fewer dependencies to the method "DoIt". This does not mean that those dependencies aren't need in the entire program (indeed, the program still makes use of DependencyA and DependencyB in the implementaiton of the factory). However, by structuring it this way, that dependency can be isolated to just the factory code, which keeps other code simpler, makes it easier to change the dependencies of DependencyC (now only the factory, itself, needs to be updated, not every place that instantiates DependencyC), and can even have certain safety/security benefits (e.g. if DependencyA and DependencyB are sensitive such as database passwords or API keys, limiing their usage to the factory reduces the chances of mishandling, compared to cases where you pass these around everywhere that you need to use the databse or API, for example).

In the example given in the book, the reason why having a factory for the Order would have helped is that it would have reduced the number of places where the constructor is used directly; only the one place that created the factory would need to be modified to store the Customer as an additional field of the factory; none of the other uses of the factory would need to be modified. By comparison, without the use of the factory, direct uses of the constructor abound, and each one of them must be updated to somehow obtain access to the Customer object.

Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200
  • 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 Apr 23 '10 at 10:05
  • 1
    @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 Apr 23 '10 at 10:54