
The Builder Design Pattern provides us with a series of methods that can act as an aid in order to let theconsumer of your class better understand what is happening under the hood.
But it is considered anAnti-Pattern by some developers.
Why use Builder Design Pattern?
It's an alternative to using multipleconstructors
by overloading them with more and more parameters.
What are the pros?
- There are tools that allow you to get hints of what the name of the parameter is, which may help if their names are informative, but it is not always the case. Like, for example: reading code on GitHub or another IDE/editor.
- You don't need to have all the data required to pass it to your object right when you initialize it.
What are the cons?
- You can end up having methods that require others to be ran in a certain order; otherwise, theconsumer will run into issues if you implement it wrong.
- The chain of methods can get really long depending on the implementation.
- Theconsumer may forget to finish up the statement with the
build()
method and not get the results they expected. - Uses more memory resources.
How can we avoid it?
Default Parameters
Kotlin supportsdefault parameters (Which is also available in other languages like C# and JavaScript).
funpow(base:Int,power:Int=2):Int{// ...}
This can work as an alternative to method overloading, since theconsumer of this method can use it like this:
pow(2)// outputs 4pow(2,3)// outputs 8
Which can make our life easier by only having to maintain a single method.
Named Arguments
This allows ourconsumers to not only type in exactly what argument they want to assign to an exact parameter, but we can also reorder them in whatever way we want. This can be handy when dealing with "legacy code" that can be hard to understand because of how many parameters requires.
pow(base=4,power=3)// outputs 64pow(power=3,base=4)// also outputs 64
Can we combine them?
Of course, my dear Watson!
pow(base=3)// outputs 9
In the example above we are passing thebase
argument as anamed argument
and thepower
is using thedefault parameter
value in our method signature.
Now that we know how to do this, we can use them to avoid the Builder Design Pattern in Kotlin.
First, let's check out the code we would have to write in Java by creating a simplified version of a Hamburgerclass
:
// Hamburger.javapublicclassHamburgerJava{privatefinalbooleanhasKetchup;privatefinalbooleanhasTomatoes;privatefinalintmeats;privateHamburgerJava(Builderbuilder){hasKetchup=builder.hasKetchup;hasTomatoes=builder.hasTomatoes;meats=builder.meats;}publicstaticclassBuilder{privatebooleanhasKetchup;privatebooleanhasTomatoes;privateintmeats;publicBuilder(intmeats){if(meats>3)thrownewIllegalArgumentException("Cannot order hamburger with more than 3 meats");if(meats<1)thrownewIllegalArgumentException("A hamburger must have at least 1 meat.");this.meats=meats;}publicBuilderaddKetchup(booleanhasKetchup){this.hasKetchup=hasKetchup;returnthis;}publicBuilderaddTomatoes(booleanhasTomatoes){this.hasTomatoes=hasTomatoes;returnthis;}publicHamburgerJavabuild(){returnnewHamburgerJava(this);}}}
Now, let's see how we can use ourHamburgerJavaclass
:
HamburgerJavadoubleMeatWithEverything=newHamburgerJava.Builder(2).addKetchup(true).addTomatoes(true).build();
Cool, maybe some of you guys are used to this.
Now let's take a look at the Kotlin implementation in our Hamburgerclass
:
// Hamburger.ktclassHamburger(valmeats:Int,valhasKetchup:Boolean=false,valhasTomatoes:Boolean=false)
Let's see how it looks when we try to use it:
valdoubleMeatWithEverything=Hamburger(meats=2,hasKetchup=true,hasTomatoes=true)
By usingnamed arguments
anddefault parameters
we can avoid the problem of not knowing what values we are being passed to each parameter and have only a single constructor to maintain.
The only cons we have with this approach is that we lose the ability to pass in values to our object after it's creation.
Which is something I don't think is that common, or is it? 🤔
Top comments(4)

- LocationSarajevo
- EducationElectrical engineer - Computer science and informatics
- WorkSoftware engineer at SaCode
- Joined
I like named parameters, they are convenient and quick to write. IMHO, a more readable approach are so called "withers", like ones fromImmutables library. You can type "with" and have autocomplete suggestion for free. :)
Also, there are some problems if you care about binary compatibility when changing case classes in Scala, seehere. IDK about Kotlin though.

@chrisvasqm what about binary compatibility? What's happened with Scala case classes, they are convenient and all, but they are breaking binary compatibility if you'll add one more parameter. How it's resolved in Kotlin?
UPD: exactly what @Sakib Hadžiavdić mentioned

You can also use thisgithub.com/jffiorillo/jvmbuilder Annotation Processor to generate the builder class automatically for you.

- LocationAlicante (Spain)
- EducationInformatics Degree @ Universidad de Alicante
- WorkStudent at Universidad de Alicante
- Joined
Another approach, more similar to what the Builder pattern does, would be the apply function:gist.github.com/AkshayChordiya/27c...
For further actions, you may consider blocking this person and/orreporting abuse