Do we ever need to prefer constructors over static factory methods? If so, when?
Asked Answered
C

4

13

I have been reading Effective Java by Joshua Bloch and so far it really lives up to its reputation. The very first item makes a convincing case for static factory methods over constructors. So much that I began to question the validity of the good old constructors :).

The advantages/disadvantages from the book are summarized below:

Advantages:

  1. They have names!
  2. We have total instance control (Singletons, performance, etc.)
  3. They can return a subtype/interface
  4. Compiler can provide type inference

Disadvantages:

  1. Private classes cannot be subclassed
  2. They do not stand out in the documentation as constructors do

The first disadvantage can actually be A Good Thing (as mentioned in the book). The second one, I think is just a minor disadvantage and can be resolved easily with the upcoming java releases (annotations for javadoc etc.)

It looks like, in the end factory methods have almost all the advantages of constructors, many many more advantages, and no real disadvantages !

So, my question is basically in three parts:

  1. Is it good practice to always use static factory methods by default over constructors?
  2. Is it ever justified to use constructors?
  3. Why don't object-oriented languages provide language level support for factories?

Note: There are two similar questions: When to use a Constructor and when to use getInstance() method (static factory methods)? and Creation of Objects: Constructors or Static Factory Methods. However the answers either just provide the above list or reiterate the rationale behind static factory methods which I am already aware of.

Credulous answered 9/3, 2012 at 15:3 Comment(3)
Also, apparently factories have even advantages for thread-safety over constructors according to this.Credulous
I read the article referenced, but came to the opposite conclusion as the author... :-) I see what is pointed out, but disagree. Perhaps it has to do with the specific usage cases that we each normally see while coding.Celio
@BrianKnoblauch, I am not expert on concurrency so I will take your word for it as the examples seem somewhat contrived :)Credulous
F
7

static factories still have to call a constructor in the end. You can move most of the functionality into the static factory, but you cannot avoid using a constructor.

On the other hand for simple cases, you can have just a constructor without having a static factory.

Constructors are the only way to set final fields, which IMHO are preferable to non-final fields.

You can use constructors can in sub-classes. You cannot use static factories for a sub-class.

If you have a good dependency injection framework to build dependencies of a component, you may find that static factories don't add much.

Freeloader answered 9/3, 2012 at 15:9 Comment(8)
Of course factories use constructors behind the scenes and that's why I included the third question. And factories can set final fields using the constructors sure. I don't understand about the sub-classes restriction you mention; care to elaborate?Credulous
Ok, it seems you talk about the 1st disadvantage there; but maybe we can provide constructors 'besides' factories for that?Credulous
"Constructors are the only way to set final fields, which IMHO are preferable to non-final fields." That right there is the big reason. Static factory methods lead down a path that makes threading hard. Final fields are a good start towards (enforced) immutability and thread friendliness. In this now multi-core world, the shift is back towards constructors and away from factories.Celio
@MadChuckle, let's say you're providing an abstract skeleton class that has some methods that need overriding. You can only use that with constructors -- either with an anonymous inner class or just with a subclass.Egwin
@BrianKnoblauch, what?! Just because you need a constructor to set final fields doesn't mean you shouldn't use a static factory method to delegate to that constructor.Egwin
@LouisWasserman You are right. My point is that you need a constructor either way, and unless the static factory is adding some real value, I would wouldn't both adding complexity.Freeloader
Hrrrrrm. Where DI is appropriate, it's really appropriate, but where it isn't, I'd almost always come down on the side of factory methods (unless you specifically want to encourage subclassing). I can't count how many times factory methods have saved me from painful and extensive refactorings.Egwin
Although I am more in line with @LouisWasserman on the preference, this answer somewhat includes the cases pointed there. I think I will use factory methods unless it is 1) very simple 2) can be solved with DI alone 3) sub-classable. I am picking this as the answer. Thanks to both of you!Credulous
S
3

I like the comment from one of the similar questions you highlighted:

(On how to decide if you should favour a factory method over a constructor),

"you need to decide what you're trying to accomplish. Either you don't want people to call your constructor (you're creating a singleton or a factory), or you don't mind (as in NumberFormat above, where they're initializing some objects for the convenience of the caller)"

To me, this means it is justified to use a constructor, where the factory method is not required. Without any need for a factory, it just makes the code harder to follow ("which exact sub-class is returned here?")

Seda answered 9/3, 2012 at 15:11 Comment(4)
Wait. But part of the point is that the caller shouldn't care what exact subclass is returned, and you can change which exact subclass is returned without having to change your callers.Egwin
True, but if those sub-classes implement that API in different ways, you'll probably need to know which exact subclass is returned, when trying to track down issues in the code. In those cirumstances, I find factory methods obscure things.Seda
@Disco3: A legitimate factory method should return something whose methods will behave, from the caller's perspective, like the parent class, but that doesn't mean the internal behavior would have to match. For example, if String were internally inheritable, concatenation of strings when one or more exceeds 256 characters could return a ConcatenatedString object which would hold an array of references to the smaller strings. All methods of ConcatenatedString would yield the same result as would a string containing all the characters from the originals, but...Xenophon
@Disco3: ...some operations would be much faster. A client shouldn't care whether it gets a ConcatenatedString which holds references to two 256-character string objects or an ArrayBackedString which held an array of 512 characters; both types should have the same semantics.Xenophon
E
3

I'm in pretty strong agreement with Josh Bloch here, and he makes the case better than I could, but here are a few places where static factories aren't as appropriate:

  • When dependency injection is more sensible; DI systems (certainly Guice) tend to inject things through their constructors. In particular, DI is appropriate when you expect that the parameters of the constructor might change in the future.
  • When you specifically intend for people to write subclasses, and you're providing a skeleton for them to implement.
Egwin answered 9/3, 2012 at 19:53 Comment(2)
Good points! Although DI systems can also be implemented by the factory pattern with some advantages (<theserverside.com/news/1363653/…), I tend to agree with you on this.Credulous
While a DI system which only knows about constructors will be limited to using constructors, and one which expects static factory methods with a particular name will be limited to classes with a method of that name, do constructors offer particular advantages from a DI perspective? Do public constructors offer any subclassing advantages over factory methods (certainly protected constructors would be needed for subclassing).Xenophon
I
0

Constructors are boring, you know exactly where to search for them, you know the scope of them, they are somehow predictable. They are there to construct the object itself, not to do god-like jobs. If you are doing too much other stuff that has not much to do with constructing the object you know you are doing something wrong. And it is not possible to "heal" this just by renaming the method. So they tend to be more focused, "better" in code quality when you have not top-of-the-line developers. (When you have the latter the points I mentioned don't matter.)

Boring stuff. Let's do something more fun and intellectual challenging...

Just for the records: I don't neglect the points mentioned in the question and other answers, I just wanted to add this additional point.

Ideal answered 9/3, 2012 at 20:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.