Builder — karmaşık nesnelerin adım adım oluşturulmasını sağlayan bir yaratım modelidir. Bir düzine parametreye sahip kurucudan farklı olarak Builder, her biri bir alanı yapılandıran bir çağrı zinciri aracılığıyla bir nesneyi birleştirir. Model, özellikle çok sayıda isteğe bağlı parametreye sahip nesneler için kullanışlıdır: ağ istemci yapılandırması, veritabanı ayarları, uyarı ve navigasyon oluşturucuları. Daha fazla bilgi için Refactoring Guru: Builder adresini ziyaret edin.
Ana Noktalar
Builder — karmaşık bir nesnenin yapısını temsilinden ayıran bir GoF yaratım modelidir. Aynı yapım süreci farklı temsiller oluşturabilir. Builder, bir nesnenin çok sayıda isteğe bağlı parametresi olduğunda ve on alanlı bir kurucu okunamaz ve esnek olmadığında kullanışlıdır. Model ayrıca, kurucu aşırı yüklemelerinin sayısının katlanarak arttığı Telescoping Constructor anti-modelini de çözer.
Builder yapısı, ana sınıfın alanlarını yansıtan alanlara sahip bir iç statik Builder sınıfı içerir. Her set-yöntemi, akıcı zincirleme için Builder (this) döndürür. Son build() yöntemi, alan değerlerini özel bir kurucuya ileterek hedef nesneyi oluşturur. Ana sınıf, bir Builder kabul eden özel bir kurucuya sahiptir. İstemci: Object.builder().setField1(val1).setField2(val2).build().
Builder ne zaman kullanılır — yalnızca 2-3'ü zorunlu olan 5+ alana sahip nesneler. Yapılandırma nesneleri (RequestConfig, DatabaseConfig). Oluşturma sırasında karmaşık doğrulama mantığına sahip nesneler. Oluşturulduktan sonra değişmez (immutable) olması gereken nesneler. Android'de, Builder SDK'da aktif olarak kullanılır: AlertDialog.Builder, Retrofit.Builder, OkHttpClient.Builder, NotificationCompat.Builder.
Kotlin'de Builder iki yaklaşıma sahiptir: klasik Java tarzı Builder (iç içe sınıf aracılığıyla) ve Kotlin tarzı DSL builder (alıcılı lambda aracılığıyla). Java tarzı Builder, Android uyumluluğu ve Java koduyla kullanım için tercih edilir. DSL builder, Kotlin'in deyimsel yoludur: bir fonksiyon, içinde this'in alanların doğrudan atanabileceği Builder bağlamı olduğu bir lambda kabul eder.
// Klasik 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)
}
}
}
// Kullanım
val config = HttpConfig.Builder()
.baseUrl("https://api.example.com")
.timeout(15_000)
.header("Authorization", "Bearer token")
.build()
Kotlin DSL builder — iç içe sınıf olmadan bir alternatif. Bir builder fonksiyonu, bir builder nesnesi bağlamında bir lambda kabul eder. Bu Kotlin için deyimseldir ve write-alanları gerektirmez. DSL builder'lar Ktor Client, kotlinx.serialization, Compose (Modifier) içinde aktif olarak kullanılır. DSL builder, Java ile uyumlu değildir ve Java API'sine sahip kütüphaneler için uygun değildir.
Swift'te Builder — Swift'in yerleşik bir Builder modeli yoktur, ancak Self döndüren yöntemler aracılığıyla akıcı bir arayüz kolayca uygulanır. Her yöntem bir özelliği yapılandırır ve self döndürür. Kotlin'in aksine, Swift ayrı bir Builder sınıfı gerektirmez — montaj sırasında değişebilir ise nesnenin kendisini döndürebilirsiniz. Değişmez nesneler için, Kotlin'e benzer şekilde iç içe bir Builder sınıfı kullanılır.
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'ı tanıttı — bildirimsel yapı oluşturma için bir dil mekanizması. SwiftUI, AttributedString, SceneBuilder result builder'lar kullanır. Bu klasik Builder'a bir alternatiftir: set-yöntemleri zinciri yerine, result builder, derleyicinin bir dizi veya ağaç halinde birleştirdiği öğeleri içeren bir kod bloğu kullanır. SwiftUI'daki @ViewBuilder en ünlü örnektir: body içinde if, switch, ForEach yazabilirsiniz ve derleyici koşullardan bir View oluşturur.
Telescoping Constructor — bir sınıfın farklı parametre kümelerine sahip birçok aşırı yüklenmiş kurucuya sahip olduğu bir anti-modeldir. Örneğin, üç kurucu: HttpConfig(url), HttpConfig(url, timeout), HttpConfig(url, timeout, retries). Parametreler arttıkça, kurucu sayısı katlanarak artar — n isteğe bağlı alan için n! kombinasyon gerekir. Builder, yalnızca gerekli alanları belirlemeye izin vererek bu sorunu çözer.
| Özellik | Telescoping Constructor | Builder | Kotlin named args |
|---|---|---|---|
| Kod miktarı | Katlanarak artış | Doğrusal artış | Minimum |
| Okunabilirlik | Düşük (hangi parametre ne?) | Yüksek (yöntem + ad) | Yüksek (ad = değer) |
| Değişmezlik | Değişmez | Değişmez | Değişmez |
| Java uyumluluğu | Tam | Tam | Yok (yalnızca Kotlin) |
| Doğrulama | Her kurucuda | build()'de — bir kez | init()'de |
Kotlin named arguments + varsayılan değerler — saf Kotlin projelerinde Builder'a zarif bir alternatiftir. Kurucu parametrelerinin varsayılan değerleri vardır, istemci yalnızca ihtiyaç duyulanları iletir: HttpConfig(baseUrl = url, timeout = 15_000). Dezavantajı, derleme zamanında zorunlu alanları doğrulayamamasıdır. Builder, Builder kurucusu aracılığıyla zorunlu alanlar sağlar (baseUrl zorunludur). Java kütüphaneleri için, Builder fiili standart olmaya devam etmektedir.
Android SDK'da Builder — standart kütüphanedeki en yaygın modellerden biridir. 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 Builder kullanmasının nedeni — geriye uyumluluk. Builder'a yeni bir yöntem eklemek mevcut kodu bozmaz. Google 20 parametreli bir kurucu kullansaydı, her yeni alan yeni bir aşırı yükleme gerektirirdi. Builder, yıllar boyunca breaking changes olmadan set-yöntemleri eklemeye izin verir. Örneğin, NotificationCompat.Builder, Android 11'de mevcut kodu etkilemeden setBubbleMetadata() ekledi.
Kotlin kütüphanelerinde Builder — Ktor (HttpClientBuilder), Coil (ImageRequest.Builder), Room (Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build()), Navigation (NavOptionsBuilder). Kotlin projelerinde, Builder genellikle DSL ile birleştirilir: Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build(). Model, geriye uyumluluk ve Java birlikte çalışabilirliğinin önemli olduğu genel API'ler için geçerliliğini korumaktadır.
Sıkça Sorulan Sorular
Builder, 1-3 alanlı nesneler için gereksizdir — normal bir kurucu veya data class daha açıktır. Java birlikte çalışabilirliği olmayan Kotlin projelerinde de gereksizdir, burada named arguments + varsayılan değerler aynı görevi daha basit bir şekilde çözer. Builder, 5+ alan, karmaşık doğrulama veya named arguments'in bulunmadığı Java API'leri için haklıdır.
Builder karmaşık bir nesneyi adım adım oluşturur (alan yapılandırması), Factory bir nesneyi türüne veya parametrelerine göre tamamen oluşturur. Builder «nasıl birleştirilir?» sorusuna, Factory «ne oluşturulur?» sorusuna yanıt verir. Builder genellikle Factory ile birleştirilir: Factory türü seçer, Builder alanları yapılandırır.
SwiftUI'de, Builder'ın rolünü result builders (@ViewBuilder, @SceneBuilder) ve View değiştiricileri (.font(), .padding()) üstlenir. SwiftUI bildirimsel bir yaklaşım ve akıcı değiştiriciler kullandığından klasik Builder gerekli değildir. UIKit bileşenleri için Builder kullanışlıdır: UIAlertController, URLRequest, NSAttributedString.
Builder normalde bir nesneyi birleştirmek için tek bir iş parçacığında kullanıldığından iş parçacığı güvenliği gerektirmez. Builder çoklu iş parçacığı ortamında (nadir durum) kullanılıyorsa, her set-yöntemini ve build()'i senkronize edin. Alternatif — Immutable Builder: her set-yöntemi, değiştirilmiş alanla yeni bir Builder örneği döndürür.
Retrofit.Builder, bir DI kabı olmadan çalışması gereken genel bir kütüphane API'sidir. Builder, Dagger veya diğer DI çerçevelerine bağımlılıklar olmadan yapılandırma esnekliği (baseUrl, dönüştürücüler, interceptors, özel çağrı bağdaştırıcıları) sağlar. Bir uygulama içinde, DI Builder aracılığıyla Retrofit'i bir kez oluşturabilir, ancak Builder'ın kendisi Retrofit'in genel API'sinin bir parçası olarak kalır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun