Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Avoiding the Builder Design Pattern in Kotlin
Christian Vasquez
Christian Vasquez

Posted on

     

Avoiding the Builder Design Pattern in Kotlin

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 thebuild() 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{// ...}
Enter fullscreen modeExit fullscreen mode

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
Enter fullscreen modeExit fullscreen mode

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
Enter fullscreen modeExit fullscreen mode

Can we combine them?

Of course, my dear Watson!

pow(base=3)// outputs 9
Enter fullscreen modeExit fullscreen mode

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);}}}
Enter fullscreen modeExit fullscreen mode

Now, let's see how we can use ourHamburgerJavaclass:

HamburgerJavadoubleMeatWithEverything=newHamburgerJava.Builder(2).addKetchup(true).addTomatoes(true).build();
Enter fullscreen modeExit fullscreen mode

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)
Enter fullscreen modeExit fullscreen mode

Let's see how it looks when we try to use it:

valdoubleMeatWithEverything=Hamburger(meats=2,hasKetchup=true,hasTomatoes=true)
Enter fullscreen modeExit fullscreen mode

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)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
sake_92 profile image
Sakib Hadžiavdić
In central Bosnia born and raised. On the computer is where I spent most of my days.
  • Location
    Sarajevo
  • Education
    Electrical engineer - Computer science and informatics
  • Work
    Software 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.

CollapseExpand
 
eugeniyk profile image
eugeniyk
  • Joined
• Edited on• Edited

@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

CollapseExpand
 
jffiorillo profile image
jffiorillo
  • Joined

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

CollapseExpand
 
putopavel profile image
Pavel Razgovorov
  • Location
    Alicante (Spain)
  • Education
    Informatics Degree @ Universidad de Alicante
  • Work
    Student 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...

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Un simple mortal
  • Location
    Santo Domingo, Dominican Republic
  • Education
    Software Engineering
  • Work
    Software Developer
  • Joined

More fromChristian Vasquez

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp