In an entry titled "Functional style in Java", Brian Slesinsky presents a
technique he
calls "half beans".
Never mind the fact that I can’t really see the connection between this and
functional programming, I find his recommendations quite questionable.
Brian is trying to solve the problems of objects that are not quite
completely initialized. In order to make sure an object is fully
initialized, he forces his class (Album) to have just one constructor that
accepts only one parameter, of type AlbumBuilder. AlbumBuilder is the
helper class in charge of making sure the object will be fully initialized.
There are a number of issues with his points.
- First of all, the name. I initially assumed that "half bean" meant
that the pattern is supposed to avoid those "half beans", those Java Beans
that are not completely initialized. Well, no. Half in this case
means that the getters are in the main class and the setters and no-op
argument are in the Builder class. And to validate his point, Brian makes the following parallel:The getters go into one class and the no-arg constructor and setters go in
the other. If it looks familar, you’re right – it’s basically the same pattern
as String/StringBuffer.String and StringBuffer certainly have no such connection. They
are two very separate classes and one just happens to use the other for its
internal implementation, but that’s just a detail. They could happily live
separately and would serve a purpose on their own, as opposed to the Album/AlbumBuilder
duo.
- Second, all the AlbumBuilder class does is postpone the problem.
Instead of making sure that Album is fully initialized, you must now put this
logic in AlbumBuilder.
- And finally, this technique introduces a lethal weakness in the application
by coupling the classes Album and AlbumBuilder in ways that are not only
invisible to the programmer but invisible to the compiler as well. For
example, if one day, the design mandates the addition of a field "Producer" to
the Album class, I have to remember to update AlbumBuilder or everything will
break.
Overall, this technique doesn’t help you address the main problem which, in
my opinion, is not where you should signal the error but rather how
you should handle it. It is much more important to decide whether such an
error should be an AssertionError, or an IllegalArgumentException or something else,
and more importantly, whether it should be recoverable or not.
On a related note, the initial motivation that made Brian come up with this
design was the absence of named parameters in Java:
Some languages solve this problem with keyword arguments, but Java doesn’t
have them, so we need another solution.
It is actually quite easy to emulate named parameters in Java. For
example:
new Album().title("The Wall").band("Pink Floyd");
This is very much un-Java, but it’s there if you decide you need it one day.