Building on my recent discussion of common method names, I wanted to add a little more detail on factory methods. Of course, this relates to Java - other languages have different conventions.
Factory methods
One of the habits I have got into is using factory methods for immutable classes and constructors for mutable ones. Like all rules, this isn't applies 100%, but it is a good place to start.
One of the benefit of factories is the ability to change the implementation class (such as to an optimised subclasss). This can tackle performance issues without affecting the main application. Similarly, the factory might return a cached instance if the class is immutable. The JDK Integer.valueOf()
method is a good example of applying a cache (although sadly there are more negative knock-on implications in Java).
But, what name should be used to define these factories?
The JDK default choice was Foo.valueOf()
. This name is perfectly usable, and has the benafit of being well-known. But it is a bit more wordy than necessary.
The JDK added to this convention with EnumSet.of()
, the Foo.of()
naming pattern. This is my favourite choice, as "of" is short and clear for most cases.
Where necessary, it can be suffixed by something descriptive, such as OffsetDateTime.ofMidnight()
or Duraton.ofSeconds() (example)
. These factories are normally a little more complex in how they go about manipulating the input parameters into the state of the class, and the Javadoc of the factory will tend to be a little more complex.
Thus Foo.of()
itself (no descriptive suffix) should be reserved for the most common case where there is no confusion as to meaning. This will typically take parameters that relate very simply to the internal state of the class (example). For example, there should be relatively little complication in the Javadoc that describes what the factory does.
Sometimes, the "of" prefix doesn't make sense. So within a given API it may make sense to deviate. In ThreeTen/JSR-310 I have a variety of other common factory names.
The DateTime.now()
variants create an instance of the class with the current time. This could be DateTime.ofNow()
, but the functionality of the factory feels sufficiently different to justify its own specific factory name. (example)
Similarly, I use a specific factory name for parsing - DateTime.parse()
. (example). Parsing is a very specific operation, that really justifies standing out in the API. Note that if the string being parsed is effectively just an identifier and therefore the actual state of the class, then I would use "of", not "parse", as in ZoneId.of("Europe/London")
.
For these more complex cases, its about clarity. For example, Duration.between(a,b)
to calculate the duration between two instants,is a lot clearer than Duration.ofBetween(a,b)
.
There are lots of possible alternatives: Foo.make()
, Foo.from()
, Foo.for()
(which requires a suffix to make a valid method name!), and many more. The advantage of "from" is that it is the opposite of "to", when converting from another type. However, in most cases, I find the consistency and simplicity of using "of" as a general factory prefix as being more useful.
And of course a key advantage of method prefix naming strategies is that you can type Foo.of
and do your IDE auto-complete to see all the available principal factories. That is a key API usability feature.
Finally, I particularly dislike factory methods that start with "get", like Foo.getFoo()
or Foo.getInstance()
. These are really confusing in all circumstances, but especially in an IDE where auto-complete after "get" really shouldn't show a factory.
Summary
I like to use Foo.of()
for most of my factory methods, supplemented by Foo.parse()
and other specialist variants. I also try to use factory methods for immutable classes, and constructors for mutable classes where possible and sensible.
Any thoughts on this? Comments welcome...
You have double paragraph: both starting with "There are lots of...".
ReplyDeleteFixed, thanks
ReplyDeleteI've started adopting many of the conventions from the Guava library (http://code.google.com/p/guava-libraries/) lately since I've found their overall code quality to be the highest among the open source projects I've seen. You'll see their immutable factories usually use of() as well (http://docs.guava-libraries.googlecode.com/git-history/v9.0/javadoc/index.html), but the also provide factories for array lists, etc.
ReplyDelete"of" makes sense when a factory is attached to the object it creates. Not particularly useful if you have a factory class.
ReplyDeleteI'm less enthused about its use when combined with descriptions, though. ofMidnight strikes me as awkward; it doesn't imply a factory (or anything else) to me. Then again, I can see the argument for consistency, and "Duration.ofSeconds" is a bit more self-explanatory.
--
"as" also makes sense as a potential conversion method prefix. There's precedent in Arrays.asList().
To parse much too finely, perhaps "as" might be preferred when no data is lost and "to" when a lossy conversion is expected (toString).
JScience also uses the "as" prefix in Amount.asType(Class), which mostly exists as a way to assert generic type in a controlled manner. That's another lossless "conversion".
[quote]JScience also uses the "as" prefix in Amount.asType(Class)...[/quote]
ReplyDeleteasXxx is generally used for instance methods that convert an object to a different representation. This is the case for JScience' Amount.asTYpe(Class) as well: http://jscience.org/api/org/jscience/physics/amount/Amount.html The same may
ofXxx() methods, on the other hand, is generally used for static factory methods that return an instance of the type (or a subtype).
Hi Stephen,
ReplyDeleteVery nice blog! Is there an email address I can contact you in private?
Nitpick, I guess, but factories (real factories) make things. "Of" does not connote production. A "constructor" clearly makes something. "new" clearly makes something. A static "create" method clearly makes something. "valueOf" is pretty close. "of" always gives me pause because there is no real implied or explicit verb. Frobnicator.of(someHairball) doesn't really tell me what someHairball is being used for. Will it become part of the returned Frobnicator? Is it an alternate representation of the Frobnicator that will be returned? Is it the raw materials necessary to boil down in order to create a Frobnicator out of their essence?
ReplyDeleteI guess I'm old school. I use "create" for the most part, or "valueOf" when my classes feel particularly JDK-ish (at least "valueOf" implies both a new object being created and a translation operation).
If a single word is greatly desired above all else, and if "create" somehow does not suffice, then "for" or "from" is often a mildly worthy replacement.