How to change the visibility of methods in a Builder design pattern ?
For example I have this Builder :
public class Builder {
public Builder a() {
//
return this;
}
public Builder b() {
//
return this;
}
}
User can use the API and do this :
new Builder().a().b();
new Builder().a();
new Builder().b();
new Builder().b().a();
I want to allow him to access method b()
only if a()
has been called :
new Builder().a().b();
new Builder().a();
A simple example could be a SQL request Builder. You shouldn't be allowed to call when()
before select()
.
How to do so?
Let's see how we can implement builder design pattern in java. First of all you need to create a static nested class and then copy all the arguments from the outer class to the Builder class. We should follow the naming convention and if the class name is Computer then builder class should be named as ComputerBuilder .
Builder in C++ Builder is a creational design pattern, which allows constructing complex objects step by step. Unlike other creational patterns, Builder doesn't require products to have a common interface. That makes it possible to produce different products using the same construction process.
Builder pattern aims to “Separate the construction of a complex object from its representation so that the same construction process can create different representations.” It is used to construct a complex object step by step and the final step will return the object.
What design pattern should you think of when you want to hide how you construct a complex object? Give only one pattern. Which design pattern would you use when you want a client to create a new object without explicitly specifying the class of the new object? Give only one pattern.
To solve this problem, there is Builder pattern to ensure the thread-safety and atomicity of object creation. Implementation : In Builder pattern, we have a inner static class named Builder inside our Server class with instance fields for that class and also have a factory method to return an new instance of Builder class on every invocation.
Implementation : In Builder pattern, we have a inner static class named Builder inside our Server class with instance fields for that class and also have a factory method to return an new instance of Builder class on every invocation. The setter methods will now return Builder class reference.
Immutable objects can be built without much complex logic in the object building process. The number of lines of code increases at least to double in builder pattern, but the effort pays off in terms of design flexibility and much more readable code. Requires creating a separate ConcreteBuilder for each different type of Product.
The process of constructing an object should be generic so that it can be used to create different representations of the same object. Product – The product class defines the type of the complex object that is to be generated by the builder pattern.
Two approaches : StepBuilder pattern, mentioned here (thanks to Eritrean) and a custom one, described after.
StepBuilder
Inside your builder class, define as many interfaces as "steps" your building should have. The returning type of a method in an interface returns to the type where the next methods should be available.
Here b()
can only be called after a()
.
public class Builder {
/*
* next available methods are defined by
* the returned interface type
*/
private static interface AStep {
BStep a();
}
private static interface BStep {
void b();
}
private static class Steps implements AStep, BStep {
BStep a() {
//
return this;
}
void b() {
//
return this;
}
}
}
Custom approach with Abstract class (I call it : the AbstractBuilder)
As I couldn't define same methods names with the StepBuilder approach I tried something else.
I defined a main Builder
with the first callable methods (visible), common methods and the build()
method (protected, because it will only be availble through other classes if needed).
I defined an abstract class, called AbstractBuilder
, with an attribute of Builder
type and a constructor setting this attribute.
I defined as many builders as steps I have. All those builders extends AbstractBuilder
and thus have common methods and ending method available if needed, by calling it on the Builder
instance.
It looks like this :
public class AbstractBuilder {
protected Builder builder;
protected AbstractBuilder(Builder builder) {
this.builder = builder;
}
}
public class Builder {
public BStep a() {
//
return new BStep(this);
}
protected Object build() {
//
return null;
}
}
public class BStep extends AbstractBuilder {
protected BStep(Builder builder) {
super(builder);
}
public CStep b() {
//
return new CStep(builder);
}
public Object build() {
return builder.build();
}
}
public class CStep extends AbstractBuilder {
protected CStep(Builder builder) {
super(builder);
}
public BStep and() {
//
return new BStep(builder);
}
public DStep c() {
//
return new DStep(builder);
}
public Object build() {
return builder.build();
}
}
public class DStep extends AbstractBuilder {
protected DStep(Builder builder) {
super(builder);
}
public CStep and() {
//
return new CStep(builder);
}
public EStep d() {
// etc. ... return new EStep(builder);
}
public Object build() {
return builder.build();
}
}
with this pattern you can manage the availability of methods after each calls and use "backwards" loops :
Builder builder = new Builder();
builder.a().b().and().a().b().c().and().b().build();
If I'm understanding your question correctly, you can do this:
public class Builder {
private boolean aProcessed;
public Builder() {
this.aProcessed = false;
}
public Builder a() {
//
aProcessed = true;
return this;
}
public Builder b() throws IllegalAccessException {
if (!aProcessed) {
throw new IllegalAccessException();
}
//
return this;
}
}
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