Builder — isang creational pattern na nagpapahintulot sa paggawa ng mga kumplikadong object nang step-by-step. Hindi tulad ng constructor na may sampung parameter, ang Builder ay nag-assemble ng object sa pamamagitan ng chain ng mga tawag, bawat isa ay nagse-set ng isang field. Ang pattern ay lalong kapaki-pakinabang para sa mga object na may maraming opsyonal na parameter: configuration ng network client, mga setting ng database, mga tagabuo ng alert at navigation. Higit pa sa Refactoring Guru: Builder.
Mga Pangunahing Punto
Builder (tagabuo) — isang GoF creational pattern na naghihiwalay sa pagbuo ng isang kumplikadong object mula sa representasyon nito. Ang parehong proseso ng pagbuo ay maaaring lumikha ng iba't ibang representasyon. Ang Builder ay kapaki-pakinabang kapag ang isang object ay maraming opsyonal na parameter at ang constructor na may sampung field ay hindi nababasa at hindi flexible. Nilulutas din ng pattern ang problema ng Telescoping Constructor — isang anti-pattern kung saan ang bilang ng mga overload ng constructor ay lumalaki nang exponentially.
Structure ng Builder ay may kasamang inner static na Builder class na may mga field na kumukopya ng mga field ng pangunahing klase. Ang bawat set-method ay nagbabalik ng Builder (this) para sa fluent chaining. Ang final na build() method ay gumagawa ng target na object, na ipinapasa ang mga halaga ng field sa pribadong constructor. Ang pangunahing klase ay may pribadong constructor na tumatanggap ng Builder. Kliyente: Object.builder().setField1(val1).setField2(val2).build().
Kailan gagamitin ang Builder — mga object na may 5+ field, kung saan 2-3 lang ang mandatory. Mga configuration object (RequestConfig, DatabaseConfig). Mga object na may kumplikadong validation logic sa paggawa. Mga object na dapat hindi mababago (immutable) pagkatapos gawin. Sa Android, aktibong ginagamit ang Builder sa SDK: AlertDialog.Builder, Retrofit.Builder, OkHttpClient.Builder, NotificationCompat.Builder.
Kotlin Builder ay may dalawang approach: klasikong Java-style Builder (sa pamamagitan ng nested class) at Kotlin-style DSL builder (sa pamamagitan ng lambda na may receiver). Ang Java-style Builder ay mas gusto para sa Android compatibility at kapag ginagamit sa Java code. DSL builder — idiomatic na paraan ng Kotlin: ang function ay tumatanggap ng lambda, sa loob nito ang this ay ang Builder context, kung saan ang mga field ay maaaring direktang italaga.
// Klasikong Builder
data class HttpConfig private constructor(
val baseUrl: String,
val timeout: Long = 30_000,
val retries: Int = 3,
val headers: Map<String, String> = emptyMap()
) {
class Builder {
private var baseUrl: String = ""
private var timeout: Long = 30_000
private var retries: Int = 3
private var headers: MutableMap<String, String> = mutableMapOf()
fun baseUrl(url: String) = apply { this.baseUrl = url }
fun timeout(ms: Long) = apply { this.timeout = ms }
fun retries(n: Int) = apply { this.retries = n }
fun header(key: String, value: String) = apply { headers[key] = value }
fun build(): HttpConfig {
require(baseUrl.isNotBlank()) { "baseUrl is required" }
return HttpConfig(baseUrl, timeout, retries, headers)
}
}
}
// Paggamit
val config = HttpConfig.Builder()
.baseUrl("https://api.example.com")
.timeout(15_000)
.header("Authorization", "Bearer token")
.build()
Kotlin DSL builder — alternatibo nang walang nested class. Ang builder-function ay tumatanggap ng lambda sa konteksto ng object-tagabuo. Ito ay idiomatic para sa Kotlin at hindi nangangailangan ng write-field. Ang DSL builders ay aktibong ginagamit sa Ktor Client, kotlinx.serialization, Compose (Modifier). Ang DSL builder ay hindi compatible sa Java at hindi angkop para sa mga library na may Java API.
Swift Builder — walang built-in na Builder pattern ang Swift, ngunit ang fluent interface ay madaling ma-implement sa pamamagitan ng mga method na nagbabalik ng Self. Bawat method ay nagse-set ng property at nagbabalik ng self. Hindi tulad ng Kotlin, hindi nangangailangan ang Swift ng hiwalay na Builder class — ang object mismo ay maaaring ibalik kung ito ay mutable sa yugto ng assembly. Para sa mga immutable object, ginagamit ang nested Builder class katulad ng Kotlin.
struct NetworkRequest {
let url: String
let method: HTTPMethod
let headers: [String: String]
let body: Data?
let timeout: TimeInterval
final class Builder {
private var url: String = ""
private var method: HTTPMethod = .get
private var headers: [String: String] = [:]
private var body: Data? = nil
private var timeout: TimeInterval = 30
func withURL(_: String) -> Self { /* self */ }
func withMethod(_: HTTPMethod) -> Self { /* self */ }
func withHeader(key: String, value: String) -> Self { /* self */ }
func withBody(_: Data) -> Self { /* self */ }
func withTimeout(_: TimeInterval) -> Self { /* self */ }
func build() throws -> NetworkRequest {
guard !url.isEmpty else { throw BuilderError.missingURL }
return NetworkRequest(
url: url, method: method, headers: headers,
body: body, timeout: timeout
)
}
}
}
Result Builders — ipinakilala ng Swift 5.4 ang @resultBuilder — isang mekanismo ng wika para sa deklaratibong pagbuo ng mga structure. Ang SwiftUI, AttributedString, SceneBuilder ay gumagamit ng result builders. Ito ay alternatibo sa klasikong Builder: sa halip na chain ng set-method, ang result builder ay gumagamit ng code block na may mga element na kinokolekta ng compiler sa isang array o tree. Ang @ViewBuilder sa SwiftUI — pinakakilalang halimbawa: sa loob ng body ay maaaring magsulat ng if, switch, ForEach, at ang compiler ay bumubuo ng View mula sa mga kondisyon.
Telescoping Constructor — isang anti-pattern kung saan ang isang klase ay maraming overloaded na constructor na may iba't ibang set ng parameter. Halimbawa, tatlong constructor: HttpConfig(url), HttpConfig(url, timeout), HttpConfig(url, timeout, retries). Sa pagtaas ng mga parameter, ang bilang ng mga constructor ay lumalaki nang exponentially — para sa n opsyonal na field ay kailangan ng n! kombinasyon. Nilulutas ng Builder ang problemang ito sa pamamagitan ng pagpapahintulot sa pag-set lamang ng mga kinakailangang field.
| Katangian | Telescoping Constructor | Builder | Kotlin named args |
|---|---|---|---|
| Dami ng code | Eksponensyal na paglaki | Linear na paglaki | Minimal |
| Pagkabasa | Mababa (aling parameter?) | Mataas (method + pangalan) | Mataas (pangalan = halaga) |
| Hindi pagbabago | Immutable | Immutable | Immutable |
| Java compatibility | Buo | Buo | Hindi (Kotlin lang) |
| Validation | Sa bawat constructor | Sa build() — isang beses | Sa init() |
Kotlin named arguments + default values — isang eleganteng alternatibo sa Builder sa mga purong Kotlin na proyekto. Ang mga parameter ng constructor ay may mga default na halaga, ang kliyente ay nagpapasa lamang ng mga kailangan: HttpConfig(baseUrl = url, timeout = 15_000). Kahinaan — hindi ma-validate ang mga mandatory field sa yugto ng compilation. Ang Builder ay nagbibigay ng mandatory field sa pamamagitan ng Builder constructor (baseUrl ay mandatory). Para sa mga Java library, ang Builder ay nananatiling de facto standard.
Builder sa Android SDK — isa sa mga pinakakaraniwang pattern sa standard library. AlertDialog.Builder: new AlertDialog.Builder(context).setTitle().setMessage().setPositiveButton().create(). Retrofit.Builder: new Retrofit.Builder().baseUrl().addConverterFactory().build(). OkHttpClient.Builder: new OkHttpClient.Builder().connectTimeout().addInterceptor().build(). NotificationCompat.Builder: setContentTitle().setContentText().setSmallIcon().build().
Bakit ginagamit ng Google ang Builder — backward compatibility. Ang pagdaragdag ng bagong method sa Builder ay hindi sumisira sa umiiral na code. Kung gumamit ang Google ng constructor na may 20 parameter, ang bawat bagong field ay mangangailangan ng bagong overload. Ang Builder ay nagpapahintulot ng pagdaragdag ng set-method sa loob ng maraming taon nang walang breaking changes. Halimbawa, ang NotificationCompat.Builder ay nagdagdag ng setBubbleMetadata() sa Android 11, nang hindi naaapektuhan ang umiiral na code.
Builder sa mga Kotlin library — Ktor (HttpClientBuilder), Coil (ImageRequest.Builder), Room (Room.databaseBuilder()), Navigation (NavOptionsBuilder). Sa mga proyektong Kotlin, ang Builder ay madalas na pinagsama sa DSL: Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build(). Ang pattern ay nananatiling may kaugnayan para sa mga pampublikong API kung saan mahalaga ang backward compatibility at Java interoperability.
Mga Madalas Itanong
Ang Builder ay kalabisan para sa mga object na may 1-3 field — ang ordinaryong constructor o data class ay mas mauunawaan. Kalabisan din sa mga proyektong Kotlin na walang Java interoperability, kung saan ang named arguments + default values ay mas simpleng nilulutas ang parehong gawain. Ang Builder ay makatwiran para sa 5+ field, kumplikadong validation, o Java API kung saan ang named arguments ay hindi available.
Ang Builder ay gumagawa ng isang kumplikadong object nang step-by-step (pagse-set ng field), ang Factory ay gumagawa ng object nang buo ayon sa uri o parameter. Ang Builder ay sumasagot sa tanong na «paano mag-assemble?», ang Factory — «ano ang gagawin?». Ang Builder ay madalas na pinagsama sa Factory: Pinipili ng Factory ang uri, ang Builder ay nagse-set ng mga field.
Sa SwiftUI, ang papel ng Builder ay ginagampanan ng result builders (@ViewBuilder, @SceneBuilder) at mga modifier ng View (.font(), .padding()). Ang klasikong Builder ay hindi kailangan dahil ang SwiftUI ay gumagamit ng deklaratibong approach at fluent modifiers. Para sa mga UIKit component, ang Builder ay kapaki-pakinabang: UIAlertController, URLRequest, NSAttributedString.
Ang Builder ay karaniwang hindi nangangailangan ng thread safety, dahil ito ay ginagamit sa isang thread para sa pag-assemble ng object. Kung ang Builder ay ginagamit sa isang multi-thread na kapaligiran (bihirang kaso), i-synchronize ang bawat set-method at build(). Alternatibo — Immutable Builder: bawat set-method ay nagbabalik ng bagong instance ng Builder na may binagong field.
Ang Retrofit.Builder ay ang pampublikong API ng library na dapat gumana nang walang DI container. Ang Builder ay nagbibigay ng flexibility ng configuration (baseUrl, converters, interceptors, custom call adapters) nang walang dependencies sa Dagger o iba pang DI. Sa loob ng application, ang DI ay maaaring gumawa ng Retrofit nang isang beses sa pamamagitan ng Builder, ngunit ang Builder mismo ay nananatiling bahagi ng pampublikong API ng Retrofit.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din