Builder Pattern vs kotlin DSL
In this article, we’ll create a Student object using Builder pattern and then we’ll use Kotlin features like extension function, lambdas, etc… to convert the Builder to DSL and finally we’ll see which one is better for object creation and why?
This article is part of a series. In part 2 we’ll learn more about application of DSL in Android. Now before moving ahead let’s look at their Definitions first.
Builder Pattern
Builder pattern is a Creational Design pattern which is used to create objects, when object contains a lots of attributes.
DSL(Domain Specific Language)
A domain-specific language is a computer language specialised to a particular application domain. For eg. SQL for database queries, CSS for style, Html for markup, Xml for data storage and transfer etc.
Java or Kotlin are GPU(general purpose languages) are on the other hand can be applied across various Application Domains.
Builder pattern in kotlin
- In Builder class, we made setter for fields private(using private set) so any property can only be initialized through their methods only i.e. name(“Jon”) and not using field initializations i.e. name = “Alex”.
- apply is an extension function that takes ‘this’ reference of the object on which it’s invoked and returns ‘this’ reference of the same object after some operation performed on that object as can be seen in below code snippet.
inline fun <T> T.apply(block: T.() -> Unit): T
DSLifying the Builder
- We have removed all functions in Builder class except build()
- student function here is where the magic happens it takes a function literal with the receiver which enables us to write this DSL.
block: Student.Builder.() -> Unit
- block is a lambda function with no inputs and no outputs but is associated with a receiver class Student.Builder
- Check this article to better understand function literal with receiver.
Default and Named arguments
One last thing for the sake of completeness since Kotlin has a feature like default and named arguments where you can define arguments with default values check function findCar for example.
Default arguments allow you to call functions with fewer arguments and hence you can use it to create objects just like Builder pattern with only the attributes you need. Read more about Default and Named arguments here.
fun findCar(
carId: Int = 0,
model: String = "",
make: String = ""
): String//this can be called using either of
findCar(carId = 1)
findCar(carId = 1, model = "BMW")
....
Named arguments make sense for fewer arguments otherwise it’s just a code smell.
DSL vs Builder
- If we check object creation of Builder vs DSL. DSL looks more readable and there is no dot operators or Builder() constructor call in case of DSL.
- No need to add all those builder methods to initialize each field in Builder class so it’s also more compact than Builder pattern.
- We can simply call function student with curly braces and attributes that we need.
Also checkout next part here to understand DSL application in Android Dialog API.