Builder — mürəkkəb obyektləri addım-addım yaratmağa imkan verən yaradıcı nümunə. Parametrləri çox olan konstruktordan fərqli olaraq, Builder obyekti zəncirvari çağırışlar vasitəsilə yığır, hər biri bir sahəni təyin edir. Nümunə çoxlu isteğe bağlı parametrləri olan obyektlər üçün xüsusilə faydalıdır: şəbəkə müştərisinin konfiqurasiyası, verilənlər bazası parametrləri, xəbərdarlıq və naviqasiya qurucuları. Ətraflı — Refactoring Guru: Builder.
Əsas məqamlar
Builder (inşaatçı) — mürəkkəb obyektin qurulmasını onun təqdimatından ayıran GoF yaradıcı nümunəsi. Eyni qurma prosesi müxtəlif təqdimatlar yarada bilər. Builder obyektin çoxlu isteğe bağlı parametrləri olduqda və on sahəli konstruktor oxunmaz və çevik olmadıqda faydalıdır. Nümunə həmçinin Telescoping Constructor problemini həll edir — bu anti-nümunədə konstruktor aşırı yüklənmələrinin sayı eksponensial olaraq artır.
Builder strukturu — əsas sinfin sahələrini kopyalayan sahələri olan daxili statik Builder sinfini əhatə edir. Hər set-metodu fluent chaining üçün Builder (this) qaytarır. Final build() metodu hədəf obyekti yaradır, sahə dəyərlərini özəl konstruktora ötürür. Əsas sinif Builder qəbul edən özəl konstruktora malikdir. Müştəri: Object.builder().setField1(val1).setField2(val2).build().
Builder nə vaxt istifadə olunmalı — yalnız 2-3-ü məcburi olan 5+ sahəsi olan obyektlər. Konfiqurasiya obyektləri (RequestConfig, DatabaseConfig). Yaradılmada mürəkkəb validasiya məntiqi olan obyektlər. Yaradıldıqdan sonra dəyişməz (immutable) olmalı obyektlər. Android-də Builder SDK-da fəal istifadə olunur: AlertDialog.Builder, Retrofit.Builder, OkHttpClient.Builder, NotificationCompat.Builder.
Kotlin Builder iki yanaşmaya malikdir: klassik Java-style Builder (iç-içə sinif vasitəsilə) və Kotlin-style DSL builder (receiver ilə lambda vasitəsilə). Java-style Builder Android uyğunluğu və Java kodu ilə istifadə üçün üstünlük təşkil edir. DSL builder — idiomatik Kotlin üsulu: funksiya lambda qəbul edir, onun daxilində this — Builder kontekstidir, burada sahələri birbaşa təyin etmək olar.
// Klassik 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)
}
}
}
// Istifadə
val config = HttpConfig.Builder()
.baseUrl("https://api.example.com")
.timeout(15_000)
.header("Authorization", "Bearer token")
.build()
Kotlin DSL builder — iç-içə sinif olmadan alternativ. Builder-funksiya qurucu-obyekt kontekstində lambda qəbul edir. Bu Kotlin üçün idiomatikdir və write-sahələri tələb etmir. DSL builders Ktor Client, kotlinx.serialization, Compose (Modifier) də fəal istifadə olunur. DSL builder Java ilə uyğun deyil və Java API-si olan kitabxanalar üçün uyğun deyil.
Swift Builder — Swift-in daxili Builder nümunəsi yoxdur, lakin fluent interface Self qaytaran metodlar vasitəsilə asanlıqla tətbiq olunur. Hər metod xassəni təyin edir və self qaytarır. Kotlin-dən fərqli olaraq, Swift ayrıca Builder sinfi tələb etmir — obyekt yığma mərhələsində mutable-dirsə, onu özü qaytarmaq olar. Immutable obyektlər üçün Kotlin-ə bənzər iç-içə Builder sinfi istifadə olunur.
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 — Swift 5.4 @resultBuilder təqdim etdi — strukturların deklarativ qurulması üçün dil mexanizmi. SwiftUI, AttributedString, SceneBuilder result builders istifadə edir. Bu klassik Builder-ə alternativdir: set-metodlar zənciri əvəzinə result builder kompilyatorun massiv və ya ağacda topladığı elementlərlə kod bloku istifadə edir. SwiftUI-də @ViewBuilder — ən məşhur nümunə: body daxilində if, switch, ForEach yazmaq olar və kompilyator şərtlərdən View qurur.
Telescoping Constructor — sinfin müxtəlif parametr dəstləri ilə çoxlu aşırı yüklənmiş konstruktorlara malik olduğu anti-nümunə. Məsələn, üç konstruktor: HttpConfig(url), HttpConfig(url, timeout), HttpConfig(url, timeout, retries). Parametrlərin artması ilə konstruktorların sayı eksponensial olaraq artır — n isteğe bağlı sahə üçün n! kombinasiya lazımdır. Builder bu problemi yalnız lazımi sahələri təyin etməyə imkan verərək həll edir.
| Xüsusiyyət | Telescoping Constructor | Builder | Kotlin named args |
|---|---|---|---|
| Kodun miqdarı | Eksponensial artım | Xətti artım | Minimal |
| Oxunaqlılıq | Aşağı (hansı parametr?) | Yüksək (metod + ad) | Yüksək (ad = dəyər) |
| Dəyişməzlik | Immutable | Immutable | Immutable |
| Java uyğunluğu | Tam | Tam | Xeyr (yalnız Kotlin) |
| Validasiya | Hər konstruktorda | build()-də — bir dəfə | init()-də |
Kotlin named arguments + default values — təmiz Kotlin layihələrində Builder-ə zərif alternativ. Konstruktor parametrlərinin standart dəyərləri var, müştəri yalnız lazım olanları ötürür: HttpConfig(baseUrl = url, timeout = 15_000). Çatışmazlıq — tələb olunan sahələrin kompilyasiya mərhələsində yoxlanılmaması. Builder tələb olunan sahələri Builder konstruktoru vasitəsilə verir (baseUrl tələb olunur). Java kitabxanaları üçün Builder faktiki standart olaraq qalır.
Android SDK-da Builder — standart kitabxanada ən geniş yayılmış nümunələrdən biri. 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().
Google nə üçün Builder istifadə edir — geri uyğunluq. Builder-ə yeni metod əlavə etmək mövcud kodu pozmur. Əgər Google 20 parametrli konstruktor istifadə etsəydi, hər yeni sahə yeni aşırı yükləmə tələb edərdi. Builder illərlə breaking changes olmadan set-metodlar əlavə etməyə imkan verir. Məsələn, NotificationCompat.Builder Android 11-də setBubbleMetadata() əlavə etdi, mövcud koda təsir etmədən.
Kotlin kitabxanalarında Builder — Ktor (HttpClientBuilder), Coil (ImageRequest.Builder), Room (Room.databaseBuilder()), Navigation (NavOptionsBuilder). Kotlin layihələrində Builder tez-tez DSL ilə birləşdirilir: Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build(). Nümunə geri uyğunluq və Java interopunun vacib olduğu ictimai API-lər üçün aktual olaraq qalır.
Tez-tez verilən suallar
Builder 1-3 sahəsi olan obyektlər üçün lazımsızdır — adi konstruktor və ya data class daha anlaşıqlıdır. Həmçinin Java interopu olmayan Kotlin layihələrində lazımsızdır, burada named arguments + default values eyni tapşırığı daha sadə həll edir. Builder 5+ sahə, mürəkkəb validasiya və ya named arguments-in əlçatan olmadığı Java API üçün əsaslandırılır.
Bir mürəkkəb obyekti addım-addım (sahələrin təyin edilməsi) yaradır, Factory obyekti növünə və ya parametrlərinə görə tamamilə yaradır. Builder «necə yığmaq?» sualına cavab verir, Factory — «nə yaratmaq?». Builder tez-tez Factory ilə birləşdirilir: Factory növü seçir, Builder sahələri təyin edir.
SwiftUI-də Builder rolunu result builders (@ViewBuilder, @SceneBuilder) və View modifikatorları (.font(), .padding()) yerinə yetirir. Klassik Builder tələb olunmur, çünki SwiftUI deklarativ yanaşma və fluent modifiers istifadə edir. UIKit komponentləri üçün Builder faydalıdır: UIAlertController, URLRequest, NSAttributedString.
Builder adətən thread-safe tələb etmir, çünki obyekti yığmaq üçün bir axında istifadə olunur. Əgər Builder çoxaxınlı mühitdə istifadə olunursa (nadir hal), hər set-metodu və build()-i sinxronizə edin. Alternativ — Immutable Builder: hər set-metod dəyişdirilmiş sahə ilə yeni Builder nümunəsi qaytarır.
Retrofit.Builder — DI konteyneri olmadan işləməli olan kitabxananın ictimai API-sidir. Builder konfiqurasiya çevikliyi (baseUrl, konvertorlar, interceptorlar, fərdi call adapterlər) verir, Dagger və ya digər DI-dən asılı olmadan. Tətbiq daxilində DI Retrofit-i Builder vasitəsilə bir dəfə yarada bilər, lakin Builder özü Retrofit-in ictimai API-nin hissəsi olaraq qalır.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun