Builder Pattern
Before understanding Builder Pattern, first understand the problem it solves.
1. Problem Without Builder
Suppose we have a User class.
class User(
val name: String,
val age: Int,
val email: String?,
val phone: String?,
val address: String?
)Now create an object:
val user = User(
“Suman”,
29,
“suman@gmail.com”,
null,
“India”
)
But imagine real Android classes with:
- 10–15 fields
- optional values
- configs
- flags
- headers
- retry counts
Then constructor becomes ugly:
User(
"Suman",
29,
null,
null,
"India",
true,
false,
3000,
5
)Problems:
- Hard to read
- Hard to remember parameter order
- Many
nulls - Easy to make mistakes
2. Builder Pattern Solution
Instead of passing everything in constructor:
val user = User.Builder()
.setName("Suman")
.setAge(29)
.setAddress("India")
.build()Now code is:
- readable
- clean
- flexible
This is Builder Pattern.
3. Real Meaning of Builder Pattern
Builder Pattern means:
Create object step-by-step.
Instead of constructing everything at once.
Get Suman Shil’s stories in your inbox
Join Medium for free to get updates from this writer.
Very common in Android because Android objects usually have many configurations.
Let’s Implement Our Own Builder
We’ll create a User object properly.
class User private constructor(
val name:String,
val age:Int
)Why private constructor?
Because we want users to create object only using Builder.
NOT like this:
User(…)You must create object using:
User.Builder().build()Basic Builder Code in Kotlin:
class User private constructor(
val name:String,
val age:Int,
val email:String?
){
class Builder{
private val name:String,
private val age:Int,
private val email : String?= null
fun setName(name:String) = {
this.name = name
}
fun setAge(age: Int) = apply {
this.age = age
}
fun setEmail(email: String) = apply {
this.email = email
}
fun build():User{
return User(name,age,email)
}
}
Usage:
fun main() {
val user = User.Builder()
.setName("Suman")
.setAge(29)
.setEmail("suman@gmail.com")
.build()
println(user.name)
println(user.age)
}What is apply?
This:
fun setName(name: String) = apply {
this.name = name
}allows chaining:
val user = User.Builder()
.setName("Suman")
.setAge(29)
.build()Without apply, you would need:
val builder = User.Builder()
builder.setName("Suman")
builder.setAge(29)
val user = builder.build()Add Validation
Builder becomes more useful when we validate before creating object.
fun build(): User {
require(name.isNotBlank()) {
"Name is required"
}
require(age > 0) {
"Age must be greater than 0"
}
return User(name, age, email, phone, address)
}val user = User.Builder()
.setAge(29)
.build()🎯 Final Thought
Builder Pattern is not just about avoiding large constructors — it helps create cleaner, more readable, and scalable Android APIs.
The real understanding comes when you ask:
👉 “Will this object become difficult to configure or maintain as it grows?”
That’s where Builder Pattern shines.
From AlertDialog to Retrofit and WorkManager, this pattern is everywhere in Android development.
If you found this helpful, follow me on Medium for more simple Android tutorials, system design concepts, and production-level Kotlin tips.
Happy coding! 🚀









