Nishan Pantha
Computer Engineer. Knows nothing in a nutshell. Learner.
constructor over population
public class Burger {
private int size;
private boolean cheese = false;
private boolean tomato = false;
private boolean lettuce = false;
private boolean pepperoni = false;
public Burger(int size, boolean cheese, boolean tomato, boolean lettuce, boolean pepperoni) {
this.size = size;
this.cheese = cheese;
this.tomato = tomato;
this.lettuce = lettuce;
this.pepperoni = pepperoni;
}
}
Burger burger = new Burger(14, true, true false, false);
As it can be seen, as the number of items to be added to the burger grows, we have to increase the number of arguments in the constructor too.
This is a very bad design practice because it becomes difficult to remember the order of arguments as well as what type of arguments are there in the arguments.
builder pattern
public class Burger {
private int size;
private boolean cheese = false;
private boolean pepperoni = false;
private boolean lettuce = false;
private boolean tomato = false;
public Burger(BurgerBuilder builder) {
this.size = builder.size;
this.cheese = builder.cheese;
this.pepperoni = builder.pepperoni;
this.lettuce = builder.lettuce;
this.tomato = builder.tomato;
}
}
public class BurgerBuilder {
public int size;
public boolean cheese = false;
public boolean pepperoni = false;
public boolean lettuce = false;
public boolean tomato = false;
public BurgerBuilder(int size) {
this.size = size;
}
public BurgerBuilder addPepperoni() {
this.pepperoni = true;
return this;
}
public BurgerBuilder addLettuce() {
this.lettuce = true;
return this;
}
public BurgerBuilder addCheese() {
this.cheese = true;
return this;
}
public BurgerBuilder addTomato() {
this.tomato = true;
return this;
}
public Burger build() {
return new Burger(this);
}
}
Burger burger = (new BurgerBuilder(14))
.addPepperoni()
.addLettuce()
.addTomato()
.build();
In the BurgerBuilder
class, all the add
method returns the builder type so that we can form the chain for subsequent addition.
Finally, build
method returns the Burger which is what we want.
Make sure you implement this design pattern according to the context otherwise it will be an overkill. :D
Thank you for the article.
I want to add couple-o-things. I'm sorry if I sound pushy, please feel free to parry my notes and point my mistakes.
Please, oh please, do use named arguments for vague stuff (concerning methods as well):
Remember about default values, which is a thing in C# and Kotlin. Sorry, Java.
Also you can place these setters inside original Burger class. Unfortunately, this way object initialization wouldn't be atomic anymore.
I just checked google, so I wouldn't suggest using double braces initialization for Java. C# initializers are OK, though, and atomic. I do not know of the same stuff for Kotlin, but its syntax for constructors is great in the first place.
Basically, the problem grows out of Java itself, because I see more elegant solutions in other languages like C# and Kotlin. At least more complex example required in order to favour builders and factories.
True that. It'd be much easier if there was a concept like named argument in languages like Java.
Yeah this is definitely pretty specific to Java and other languages that don't have that nice syntactic sugar C# does. Articles like these really make me realize how much C# spoils us!
I wrote the burger builder in my own preferred pattern. dev.to/jtlunsford/build-a-differen... Didn't care much for the chaining though I do find chaining nice if I need to pass the object around my application before we call it finished
Cool. Yeah, it's all about the use cases in the end.
In this code, can you tell me what font you use? It's very nice
right click > inspect > "font-family: monospace;"
It's the default monospace font for your current environment:
Thanks
I am using the default one that dev.to is providing.
I'm a huge fan of returning
this
with java builder patterns. The fluent api you get out of it is fantastic. You can very nearly get something like a custom DSL out of just that technique aloneTrue that. The chain rules are elegant and are more aesthetic in builder patterns.
There is an error in
size
variable declaration inBurgerBuilder
class:instead of:
The same is for
Burger
class.Thank you for sharing.
thanks for pointing out the typo...
Aren't you duplicating the set of Boolean parameters? Why not create an instance of Burger in the BurgerBuilder constructor and return it when calling build().
Oh, I see, that way Burger won't be immutable.
Yeah. The whole point is to avoid the constructor of Burger being populated. This way, it will allow you to create chained calls to the builder and yes the side effect is the immutability of Burger subsequently.
There is a really great post about design patterns on GitHub, if you want to dig about this : github.com/kamranahmedse/design-pa...
I just realised I've never really understood it before. I think the difference comes from the pragmatic use case, aka "the constructor has loads of arguments" + a nice a short none specific example. I'd like to read something this clear for every design pattern.
Thanks. I might do similar post for other patterns I havebeen using.