Implementing the Builder pattern in Kotlin

To solve the same problems as the Builder pattern in Kotlin, we can turn to default parameter values and named arguments. Remember that the key problem the Builder pattern solves is allowing client code to easily configure different representations of some class without having to know about or understand any optional parameters that are not relevant to current usage. This is something that functions in Kotlin provide out of the box through default parameter values and named arguments. Let's take a look at how we could rewrite our SearchRequest class in Kotlin to make it easier to configure without the use of a Builder.

To achieve the same results in Kotlin, we can reimplement SearchRequest using a simple data class along the lines of the following:

data class SearchRequest(
val queryTerm: String = "",
val categories: List<String> = listOf(),
val resultCount: Int = 10
)

In this data class, we've added each property to our primary constructor and provided a default value for each of these properties. This enables us to instantiate an instance of this class by passing 0, 1, or all of the parameters. Any parameter that is not specified will rely on the default value. The following code snippet demonstrates how we can instantiate instances of SearchRequest by passing 0, 1, or multiple parameters to the constructor:

fun main() {
val request1 = SearchRequest()
val request2 = SearchRequest(
categories = listOf("Kotlin", "Android"),
queryTerm = "Kotlin"
)
val request = SearchRequest(resultCount = 20)
}

We see in this example that we can configure different representations of SearchRequest quite simply without the use of a Builder. Default parameter values allow us to only specify which parameters we care about, and named arguments let us pass those parameters in any order we wish. This frees us from having to understand the exact order of the parameters and what sensible defaults might be.

While the Builder concepts are still applicable in Kotlin, the actual requirement of a Builder class is not. This is one of the best examples of Kotlin incorporating common Java patterns and best practices into the language feature set itself.

In the next section, we'll explore how higher-order functions simplify how we can realize the Strategy pattern in Kotlin.