I\'m familiar with the idea and benefits of a static factory method, as described in Joshua Bloch\'s Effective Java:
My current favorite example of this pattern is Guava's ImmutableList. Instances of it can only be created by static factories or a builder. Here are some ways that this is advantageous:
ImmutableList
doesn't expose any public
or protected
constructors, it can be subclassed within the package while not allowing users to subclass it (and potentially break its immutability guarantee).ImmutableList.of()
factory method returns a singleton instance of EmptyImmutableList
. This demonstrates how a static factory method doesn't need to create a new instance if it doesn't have to.ImmutableList.of(E)
method returns an instance of SingletonImmutableList
which is optimized because it will only ever hold exactly 1 element.RegularImmutableList
.copyOf(Collection)
static factory method also does not always need to create a new instance... if the Collection
it is given is itself an ImmutableList
, it can just return that!The simple case. Suppose you have a class which operates some sort of printer, but it doesn't care if it is epson, canon or something else. So, you just create an Interface Printer
, create some implementations of it and create a class which has only one method: createPrinter.
So, the code will be simple:
public interface Printer {
print();
}
class CanonPrinter implements Printer {
print() {
// ...
}
}
public PrinterFactory {
Printer createPrinter() {
if (... ) {
return new CanonPrinter();
} else {
return new EpsonPrinter();
}
}
}
client code:
Printer printer = PrinterFactory.createPrinter();
printer.print();
Here you abstract you clinet code from any details of what printers you can operate with or how they manage printing. It's PrinterFactory who cares what printer to choose if one for example malfunctions.
Wouldn't Calendar.getInstance()
be a good exmaple?
It creates depending on the locale a BuddhistCalendar, JapaneseImperialCalendar or by default a GregorianCalendar.
The textbook example of your second point is Integer.valueOf(int) (similar for Boolean
, Short
, Long
, Byte
). For parameter values -128 to 127, this method returns a cached instance instead of creating a new Integer
. This makes (auto)boxing/unboxing much more performant for typical values.
You can't do that with new Integer()
since the JLS requires that new
create a new instance every time it is called.
Use javax.swing.BorderFactory
as an example of all three points.
This class is used to make borders for swing objects. These border objects can be easily re-used, and this factory method allows for this. Here is the javadoc. This factory is a great example of all three points:
createEmptyBorder()
and createEtchedBorder()
.Border
itself is actually an interface, so all objects created through this factory are actually classes which implement this interface.Here is one I had to do a while back. At a job interview, I was asked to program a deck of cards where they can be shuffled. Really simple problem. I created:
Card:
suit
rank
Deck:
card[]
I think what was the distinguishing factor is that there can only 52 cards at all times. So I made the constructor for Card() private and instead create static factory valueOf(suit, rank) This allowed me to cache the 52 cards and make the immutable. It taught many important basic lessons in that books.
This is similar to Boolean and Byte, except I used a common homework example to show why its important to control the instances. I also created a helper function for deck called newDeck() because I wanted to show an instance where the constructor might not need to be private but it would still be nice to have a helper static factory.
I hope this helps!