I'm having troubles finding out whether using a builder is the right approach when creating a object that's "partially" mutable, i.e. some of the object's properties are variable.
Let's consider this implementation of an IGlass
interface. One final mandatory parameter, one optional parameter that can be changed after object creation:
public class SimpleGlass implements IGlass {
// Mandatory.
private final int size;
// Optional.
private boolean isEmpty;
private SimpleGlass(SimpleGlassBuilder builder) {
size = builder.getSize();
isEmpty = builder.isEmpty();
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return isEmpty;
}
@Override
public void setEmpty(boolean isEmpty) {
this.isEmpty = isEmpty;
}
public static class SimpleGlassBuilder {
// Mandatory.
private final int size;
// Optional.
private boolean isEmpty = false;
public SimpleGlassBuilder(int size) {
this.size = size;
}
public SimpleGlassBuilder setEmpty(boolean isEmpty) {
this.isEmpty = isEmpty;
return this;
}
public IGlass build() {
return new SimpleGlass(this);
}
public int getSize() {
return size;
}
public boolean isEmpty() {
return isEmpty;
}
}
}
So the builder creates mutable objects, however, whenever a builder is mentioned in programming literature it's about immutable objects.
Is it okay to use a builder in cases like this?
I would say that a Builder is used for classes with a lot of properties, most of which are optional to specify. Rather than having a million constructors, or one awful constructor, you use a builder and specify just what you need.
new GlassBuilder(16_OZ).withHandle().withLogo(logo).build()
// instead of
new Glass(16_OZ,
/* handle? */ true,
/* chipped? */ false,
/* monogram? */ null,
/* something else? */ null,
logo);
Mutability is nice at the end, because mutability is nice, but it doesn't actually affect whether the Builder made your life easier.
I would leave the "empty" property in the IGlass implementation class but remove it from the builder. There are too many places to set the value. Plus it confuses the issue if you set it in the builder as that only applies to IGlass instances created after that point and only until their 'setEmpty()' method is called.
I suggest you build them and then set the 'empty' property on the newly built object instance.
The purpose of design patterns is to make things easy to talk about and easy to understand. By adding the additional concern of whether the builder or the instance is setting the 'empty' property, things are no longer so easy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With