Re: a question about factory method
On 12/18/2014 8:57 AM, John wrote:
Hi:
I am reading a very good web site
http://www.javapractices.com/topic/TopicAction.do?Id=21
I have a question about the following code:
public final class ComplexNumber {
/**
* Static factory method returns an object of this class.
*/
public static ComplexNumber valueOf(float aReal, float aImaginary) {
return new ComplexNumber(aReal, aImaginary);
}
/**
* Caller cannot see this private constructor.
*
* The only way to build a ComplexNumber is by calling the static
* factory method.
*/
private ComplexNumber(float aReal, float aImaginary) {
fReal = aReal;
fImaginary = aImaginary;
}
private float fReal;
private float fImaginary;
//..elided
}
The code uses a private constructor and the factory method. I also notice this class is an immutable class. If I write this class, I would simply have a public constructor, like:
public final class ComplexNumber {
public ComplexNumber(float aReal, float aImaginary) {
fReal = aReal;
fImaginary = aImaginary;
}
private float fReal;
private float fImaginary;
//..elided
}
Could you explain to me why their code is better than mine? If theirs is singleton, I would agree. But in this case, it does not make sense for using singleton. The only thing I can think of is using their code is more like following a trend, e.g. String.valueOf(xxx).
I guess most people will do what I do here.
The page mentions some of the things factory methods can do that
constructors cannot, then gives an example that doesn't show off any
of the differences ... Is that why you call the page "very good?" :)
A factory method can have a name, but a constructor cannot. That
means a class can have only one constructor with a particular argument
"signature," because if it had two constructors with identical calls
there'd be no way to tell which one each `new' wanted to invoke. If
you wanted to construct ComplexNumbers from either a pair of Cartesian
coordinates ("real and imaginary") *or* from a pair of polar coordinats
("magnitude and phase"), you couldn't do it with two constructors each
taking two `float' arguments. You could, however, add a factory
method like
public static ComplexNumber polarValue(float r, float t) {
return new ComplexNumber((float) (r * Math.cos(t)),
(float) (r * Math.sin(t)));
}
A factory method can recycle existing objects, but a constructor
must always initialize a brand-new object distinct from everything else
that already exists. This can save memory (and perhaps initialization
time) for immutable "value" objects: How many identical copies of
Boolean.FALSE do you need, anyhow? Since the internals of ComplexNumber
are a pair of floating-point values there might not be much benefit to
caching a whole lot of them, but perhaps it might be worth while to
use and re-use and re-re-use a few common values:
public final class ComplexNumber {
public static final ZERO = new ComplexNumber(0, 0);
public static final ONE = new ComplexNumber(1, 0);
public static final I = new ComplexNumber(0, 1);
public static ComplexNumber valueOf(float r, float i) {
if (r == 0 && i == 0) {
return ZERO;
else if (r == 1 && i == 0) {
return ONE;
} else if (r == 0 && i == 1) {
return I;
} else {
return new ComplexNumber(r, i);
}
}
... constructor and elisions as before ...
}
Finally, a factory method can return an instance of any class
that's assignable to its return type, not just an instance of its
very own class. I can't think of a ComplexNumber variant that would
be a plausible example, but consider something like Calendar. Its
getInstance() methods usually return a GregorianCalendar instance,
but could (if Locales and so on were set up) return an instance of
MayanCalendar or JulianCalendar or BabylonianCalendar or whatever:
Classes whose names, whose very existence, might not have been known
when the calling code was written. All the caller cares about is
that the returned object is a Calendar subclass, *any* Calendar
subclass. True, the caller could use a `switch' or something to
choose which of many class-specific `new' operations to execute,
but then the caller would have to enumerate all the possibilities
in advance -- and would have to issue a code update when NASA sends
colonists to Mars and they invent a MartianCalendar.
Summary: Constructors are often appropriate, but there are things
factory methods can do that constructors cannot.
--
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM