1. Introduction

In this quick article, we’ll see how to implement the Builder Design Pattern in Kotlin.

2. Builder Pattern

The Builder pattern is the one that people often use but rarely create on their own.

It’s great to handle the building of objects that may contain a lot of parameters and when we want to make the object immutable once we’re done constructing it.

To learn more, have a look at our tutorial on Creational Design Patterns here.

3. Implementation

Kotlin provides many useful features such as named and default parameters, apply() and data class which avoiding the use of classical Builder pattern implementation.

For that reason, we’ll see first a classical Java-style implementation and then a more Kotlin style short form.

3.1. Java-Style Implementation

Let’s start creating one class – FoodOrder – which contains read-only fields since we don’t want outer objects to access them directly:

class FoodOrder private constructor(builder: FoodOrder.Builder) {

    val bread: String?
    val condiments: String?
    val meat: String?
    val fish: String?

    init {
        this.bread = builder.bread
        this.condiments = builder.condiments
        this.meat = builder.meat
        this.fish = builder.fish

    class Builder {
        // builder code

Notice that the constructor is private so that only the nested Builder class can access it.

Let’s now move on to creating the nested class which will be used to build objects:

class Builder {

    var bread: String? = null
      private set
    var condiments: String? = null
      private set
    var meat: String? = null
      private set
    var fish: String? = null
      private set

    fun bread(bread: String) = apply { this.bread = bread }
    fun condiments(condiments: String) = apply { this.condiments = condiments }
    fun meat(meat: String) = apply { this.meat = meat }
    fun fish(fish: String) = apply { this.fish = fish }
    fun build() = FoodOrder(this)

As we see, our Builder has the same fields as the outer class. For each outer field, we have a matching setter method.

In case we have one or more mandatory fields, instead of using setter methods, let’s make a constructor set them.

Note that we’re using the apply function in order to support the fluent design approach.

Finally, with the build method, we call the FoodOrder constructor.

3.2. Kotlin-Style Implementation

In order to take full advantage of Kotlin, we have to revisit some best practices we got used to in Java. Many of them can be replaced with better alternatives.

Let’s see how we can write idiomatic Kotlin code:

class FoodOrder private constructor(
  val bread: String?,
  val condiments: String?,
  val meat: String?,
  val fish: String?) {

    data class Builder(
      var bread: String? = null,
      var condiments: String? = null,
      var meat: String? = null,
      var fish: String? = null) {

        fun bread(bread: String) = apply { this.bread = bread }
        fun condiments(condiments: String) = apply { this.condiments = condiments }
        fun meat(meat: String) = apply { this.meat = meat }
        fun fish(fish: String) = apply { this.fish = fish }
        fun build() = FoodOrder(bread, condiments, meat, fish)

Kotlin comes with named and default parameters that help to minimize the number of overloads and improve the readability of the function invocation.

We can also take advantage of Kotlin’s data class structure that we explore more in another tutorial here.

Finally, as well as in Java-style implementation, apply() is useful for implementing fluent setters.

4. Usages Example

Briefly, let’s have a look at how to build FoodOrder objects using these Builder pattern implementation:

val foodOrder = FoodOrder.Builder()
  .bread("white bread")
  .condiments("olive oil")

5. Conclusion

The Builder Pattern solves a very common problem in the object-oriented programming of how to flexibly create an immutable object without writing many constructors.

When considering a builder, we should focus on whether or not the construction is complex. If we have too simple construction patterns then the effort of creating our flexible builder object may far exceed the benefit.

As always, the code is available over on Github.

Inline Feedbacks
View all comments
8 months ago

Thank you so much, It was very useful. I could get the difference between creating a builder in Java and Kotlin.

Marcus Held
8 months ago

I don’t agree with the proposed solution. Imo using the builder pattern (in this form) is not idiomatic to Kotlin and can be elegantly solved by utilizing named and default parameters in the constructor. I’d even argue that using this pattern introduces a bunch of problems in your code which are not helpful like the potential of creating inconsistent objects. Also the example is not well chosen since it’s contract is unclear. Is it allowed to have an empty FoodOrder? Since I saw the application of this article in a project on mine I wrote a full argumentation in a… Read more »

Loredana Crusoveanu
Loredana Crusoveanu
8 months ago
Reply to  Marcus Held

Thanks, Marcus, I think you’re right.

We’ll work on updating the article.

Comments are closed on this article!