Factory Methods vs. Constructors?

I just read some stuff in Agile Java about factory methods and constructors. Specifically, we (my imaginary class and me, I suppose) made a constructor private and replaced it with a factory method. And… I am not entirely clear on why we did this.

I did read it. He said:

By doing so, you will have control over what happens when new instances of [Class] are created.

But I’m curious. What kind of control?

(I know I should read about design patterns. But I am not ready for that, and I’m curious now!)

GeePaw sez…

The main thing to know about ‘factory’ is the idea you already have. In all the variations, the mechanism is “keep some caller Fred.function() from saying ‘new Barney(…)’ itself.”

Let’s start with an intermal factory method. This is just a method on Fred, call it createBarney(), that makes Barney’s for the rest of Fred’s functionality. There are ┬áseveral good reasons we might want to control how the Barney’s are made:

  • ‘new Barney(…)’ takes 82 arguments, but Fred always only needs two variants based on the seventh argument. We write a createBarney() ┬áthat takes one arg and uses ‘Fred-local’ constants for the other 81.
  • ‘Barney has 82 constructors, but there are only five variants Fred ever needs, so we write five creates, createHappyBarney, createSadBarney, createDopeyBarney, and so on. Here we’re taking control over the space of names, so that our intent is as clear as possible.
  • When Freds make a new Barney, he always does the same four calls right after the new. We write a createBarney() that does the new AND the four calls.
  • Fred’s algorithm is identical to the algorithm its descendants use, except each descendant starts with a different Barney object. Pull the algo up to Fred, but use an overridable createBarney supplied by the children. (This is a Template Method where the createBarney() is the part Fred doesn’t know how to do.)
  • Barney doesn’t work or play well with others for microtesting. We write createBarney() so we can override it while testing, and substitute a FakeBarney that makes the testing easy.
  • All Barney’s are part of a memory pool, so we want our ‘createBarney’ to always return the oldest Barney object in our pool.
  • Fred can come to needing a new Barney through a dozen different paths, but we want him to only ever get one Barney and re-use it, and we don’t want to make it in advance. This is a special case of the previous one, really.

That oughta be reason enough and complication enough to keep you entertained for a while. Notice that only a couple of the above reasons are part of a good TDD approach. The rest are mostly about living with at least one poorly designed class.

I will go on and say that there are at least four variations on the factory theme:

  1. an internal factory method, as above, be it static or member.
  2. an external factory method, most commonly a static on Barney, so that any old outsider can use it to create a Barney. (This is usual for the Singleton case the folks mention below. Do not use singletons. At all.)
  3. a Factory class, BarneyFactory, does nothing else on earth but make Barney’s. (This is what most people mean when they say Factory.)
  4. an AbstractFactory is the parent class of a whole hierarchy of factories. This is rare, but invaluable when Fred needs to both ‘new’ objects AND connect them to each other without knowing how the relationship is made.

Phew.

That was fun.

6 thoughts on “Factory Methods vs. Constructors?

  1. Todd Kaufman

    Check out the Singleton pattern for an example of the approach, but the most common application is limiting the number of instances (ie. when the class is a broker for a file or database connection).

    Reply
  2. Sean McMillan

    Singleton is terrible by the way — A design smell all on its own.

    When you use a constructor, you always get back a new object. Sometimes, you might not want to get back a new object — say there should only ever be one database connection at a time; you’ll want to return the existing database connection if it is requested again. A factory will let you do so; A raw constructor will not. (Presuming that your database allows multiple simultaneous users, of course.)

    Or suppose you’re accessing a web service: now you have a local copy, which is free, and a remote copy, which costs money. You only want to use the remote copy if the local copy is bogged down. For the sake of example, you happen to know that you can serve ten concurrent users from the local copy. So you could make a factory that returns an instance of either LocalService or RemoteService, depending on how many users are logged in. This lets you hide which kind of service is actually being provided — only the factory needs to know. (both kinds will have to implement an interface, and the factory would have to return that interface type. Or a base class. Whatever.)

    Reply
  3. Angela Post author

    @Todd, thanks, that helped. I hadn’t thought of limiting the number of instances, I think because I’m not naturally thinking Object Oriented yet.

    And so, Singleton pattern is for cases where only one instance of a class should be created? I expect I’ll learn more about this as I go. I only skimmed the Wikipedia article about it, because I want to think about it more before reading.

    @Sean, is your objection just that it’s used when it’s not necessary? All I have to go on is Wikipedia, as this is all new to me: “Some consider it an anti-pattern, judging that it is overused, introduces unnecessary limitations in situations where a sole instance of a class is not actually required..”

    Thanks, by the way, for the additional detail about why one might want a factory method instead of a constructor. It’s much clearer now.

    Reply
  4. Todd Kaufman

    @Sean, I’d avoid blanket negative statements like “Singleton is terrible” without backing opinion when talking to people trying to learn.

    @Angela, Singletons are extremely overused and in Java they have a propensity for leaving you open for synchronization issues but I wouldn’t fault the pattern for that. It makes sense when using an object to represent a heavyweight resource with a single instance per vm. Your train of thought here is really dancing around dependency injection, have you investigated that (also called Inversion of Control)?

    Reply
  5. Angela Post author

    I don’t know about dependency injection yet. I’m a complete n00b at Java. That is, I’m about a quarter of the way through _Agile_Java_, and asking way too many questions way too early. :)

    I am really intrigued about dependencies and the way things fit together in OO. I’m clear on two things: 1) I don’t get it yet, and 2) There’s something really interesting there to get.

    Reply
  6. Angela Post author

    Thanks, Mike! That really made a lot of sense. Well, the 65% that I understood did… :) But I will be able to go back and get more of it later.

    Very much interested in figuring out this part:

    Notice that only a couple of the above reasons are part of a good TDD approach. The rest are mostly about living with at least one poorly designed class.

    That is, I’m excited about learning the difference.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>