Tuesday, 24 Feb 2004
External Constructors
I came up with another technique for constructing immutable objects
that I like better than Half-Beans
and Struct
Arguments. By writing a copy constructor that takes an interface
rather than a class, I can then put constructor methods for the class
in any package.
For example:
public interface WidgetSource {
String getA();
String getB();
String getC();
}
public class Widget {
private final String a;
private final String b;
private final String c;
public Widget(WidgetSource src) {
this.a = src.getA();
this.b = src.getB();
this.c = src.getC();
checkInvariants();
}
[... rest omitted ...]
}
Here's an example of how to write an external constructor:
/** creates a Widget from a DOM element */
static Widget newWidgetFromXML(final Element elt) {
WidgetSource src = new WidgetSource() {
public String getA() { return elt.getAttribute("a"); }
public String getB() { return elt.getAttribute("b"); }
public String getC() { return elt.getAttribute("c"); }
};
return new Widget(src);
}
The anonymous inner class emulates keyword arguments in Java. This is
especially useful when writing constructors for classes that have many
properties, since it's easier to read an inner class with 20 methods
than a constructor call with 20 arguments.
Another nice thing is that it's type-safe. If I need to add a new
property to Widget, I'll add the new instance variable, update the
constructor, update the WidgetSource interface, and compile. The
compiler reports a unimplemented method error for each external
interface, making it easy to find and update them.
For another example, here's how to create a Widget from a row in a
database:
/** constructs a Widget from the current row in ResultSet */
static Widget newWidgetFromRow(ResultSet rs) throws SQLException {
final String a = rs.getString("a");
final String b = rs.getString("b");
final String c = rs.getString("c");
WidgetSource src = new WidgetSource() {
public String getA() { return a; }
public String getB() { return b; }
public String getC() { return c; }
};
return new Widget(src);
}
This is slightly more tricky. I had to call the ResultSet outside of
the getter methods because they throw SQLException, and the getter
methods aren't declared to throw an exception. The same applies if
you're reading the properties from a file (due to the IOException),
and also whenever the properties need to be read in a paticular order
(such as from a stream). On the other hand, putting the code directly
in the getters themselves is more convenient when the properties can
be read in any order and there are no checked exceptions.
So why not write ordinary constructors and put them in class itself?
Typically it's because the constructor belongs in a different layer of
the system. For example, newWidgetFromRow() probably belongs in the
persistence layer, while the UI might have newWidgetFromHttpForm().
Ordinarily, setter methods would be used for this, but if you want to
have immutable objects, you can't use setters - they have to be
constructors.
respond | link |
/code
|