Brian Slesinsky's Weblog
 
   

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.