I have a Java factory method with a varargs array of Object
s at the end. The array can contain any combination of String
s and ScaledJpeg
s. The theory being that an HTML table cell can contain any number of text nodes or <image>
nodes and it will line-wrap the images as though they were just funny-shaped words.
// constructor
public Cell(TextStyle ts, float w, CellStyle cs, Object... r) {
if (w < 0) {
throw new IllegalArgumentException("A cell cannot have a negative width");
}
if (r != null) {
for (Object o : r) {
if ( (o != null) &&
!(o instanceof String) &&
!(o instanceof ScaledJpeg) ) {
throw new IllegalArgumentException(INVALID_ROW_TYPE_STR);
}
}
}
textStyle = ts; width = w; cellStyle = cs; rows = r;
avgCharsForWidth = (int) ((width * 1220) / textStyle.avgCharWidth());
}
In Scala, I might use a list of Either[String,ScaledJpeg]
. But some day I'll probably make this method allow something else, say another nested Cell
, but doing so would break existing code that only expected two possible types. At least the way it is, future changes won't break existing code.
The current solution works, allows for expansion, and is relatively easy to use, except that it defeats type safety and can only throw an exception at runtime if someone passes something unexpected as a vararg. For instance, I just forgot to add toString()
to a StringBuilder
and it blew up at runtime. So already that's a third class to account for (Since toString()
is defined on every object, I don't want to call it on whatever is passed because doing so for most object types would be an error much further down in the code violating the fail-fast behavior of this example).
java.lang.String
can't implement any new interfaces and that's probably a good thing. Even if I could make a wrapper class, everything about the way text and images are treated by this class is completely different except that they are line-wrapped together the way they would be in HTML (or in a Word doc).
As I write this, it occurs to me that I should probably use a Builder pattern, make a CellBuilder
class that has addText()
and addImage()
methods that does away with the varargs constructor. This would encapsulate the underlying List in a way that the user of the API gets 100% compile-time type safety. But out of curiosity, I'm still posting this in case there are other creative and possibly better solutions out there.