Typical usage:
Widget = new WidgetCreator() .settingThis() .andThat(foo) .squidgability(0.9) .create();This is a neat idea written up by DavidHarvey at http://www.davethehat.com/articles/aa.pdf
Bjarne Stroustrup also suggests this idiom in a C++ book (I think TheDesignAndEvolutionOfCpp [FixMe]). I use it a fair bit in CeePlusPlus, it strikes me as neat, although obviously not for compulsory arguments as there is no (simple!) way to force the client to set all the right things.
The drawback of this approach is that it does not work with inheritance because Java does not allow methods to be overridden with covariant return types.
E.g. you would like to be able to do this...
class Widget { ... } class WidgetCreator { WidgetCreator squidgability( double d ) { ... } ... }...but you can't. J2SE 1.5 will allow covariant return types! Yay! --TimMooreclass Gadget extends Widget { ... } class GadgetCreator extends WidgetCreator { GadgetCreator squidgability( double d ) { ... } ... }
Given a class with 6 instance variables a--f, you can avoid writing 64 constructors by using set methods as in the example above (but this won't work with inheritance). It also is not JavaBean-compliant, if you care about such things.
public C setA(int val) { a = val; return this; } ... C x = new C().setA(1).setC(3).setE(5);Or, you could create an anonymous subclass with a non-static initializer block with code like:
C x = new C() {{ a = 1; c = 3; e = 5; }};Of course, a--f need to be public. I suppose you could compromise:
public void setA(int val) { a = val;} ... C x = new C() {{ setA(1); setC(3); setE(5); }};Peter Norvig also suggests that if you reject this solution you use C++ for its optional arguments, or you use LISP for its keyword arguments.
One problem I realized with this is that it interferes with a common method of WritingEqualsMethods. That method requires you to use getClass() to check that the argument is of the same class as this to make equals() symmetric.
An example of applying this method is:
// In class C public boolean equals(Object o) { if (this.getClass() == o.getClass()) { C c2 = (C) o; return (a == c2.a) && (b == c2.b) && ...; } else { return false; } }However, Norvig's method causes strange results here:
C x = new C() {{ setA(1); setC(3); setE(5); }}; C y = new C(); y.setA(1); y.setC(3); y.setE(5); boolean b = x.equals(y); // Always false.I'm not sure what the best method to use is.
Very neat! But this creates even more additional classes, so could cause a problem for applet writers.--AnonymousDonor
Yes, it increases the cost of deployment. Also, objects created this way cannot usefully be serialized. Since any object created in this way is the unique instance of an otherwise inaccessible class, it cannot be deserialized from a stream. I am not sure I would ever use this idiom.--EricJablow
This page mirrored in JavaIdioms as of April 29, 2006