Builder — พื้นฐานของรูปแบบ builder ในการพัฒนาแอปมือถือ

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-02-17 เวลาอ่าน: 7 นาที

Builder — รูปแบบการสร้างที่อนุญาตให้สร้างวัตถุที่ซับซ้อนทีละขั้นตอน แตกต่างจากคอนสตรักเตอร์ที่มีพารามิเตอร์หลายสิบตัว Builder ประกอบวัตถุผ่านลูกโซ่ของการเรียก แต่ละครั้งกำหนดค่าหนึ่งฟิลด์ รูปแบบนี้มีประโยชน์โดยเฉพาะสำหรับวัตถุที่มีพารามิเตอร์เลือกได้จำนวนมาก: การกำหนดค่าไคลเอ็นต์เครือข่าย การตั้งค่าฐานข้อมูล ตัวสร้างการแจ้งเตือนและการนำทาง เรียนรู้เพิ่มเติมที่ Refactoring Guru: Builder

ประเด็นสำคัญ

  • Builder — การสร้างวัตถุทีละขั้นตอนแยกกระบวนการและผลลัพธ์
  • Fluent interface — ลูกโซ่ของการเรียก set()/with() เพื่อการกำหนดค่าที่สะดวก
  • ความไม่เปลี่ยนแปลง — Builder สร้างวัตถุที่พร้อมใช้งานซึ่งไม่ต้องใช้ setter
  • ความเข้ากันได้ย้อนหลัง — สามารถเพิ่มฟิลด์ใหม่ใน Builder โดยไม่ทำลายโค้ดที่มีอยู่
  • Kotlin DSL vs Builder — Kotlin นำเสนอ type-safe builders เป็นทางเลือก

Builder คืออะไร: แก่นแท้ของรูปแบบผู้สร้าง?

Builder — รูปแบบการสร้าง GoF ที่แยกการสร้างวัตถุที่ซับซ้อนออกจากการแสดงผล กระบวนการสร้างเดียวกันสามารถสร้างการแสดงผลที่แตกต่างกัน Builder มีประโยชน์เมื่อวัตถุมีพารามิเตอร์เลือกได้จำนวนมากและคอนสตรักเตอร์ที่มีสิบฟิลด์อ่านยากและยืดหยุ่นไม่ได้ รูปแบบนี้ยังแก้ปัญหา Telescoping Constructor ซึ่งเป็นปฏิรูปที่จำนวนการโอเวอร์โหลดของคอนสตรักเตอร์เพิ่มขึ้นแบบทวีคูณ

โครงสร้างของ Builder รวมถึงคลาส Builder คงที่ภายในที่มีฟิลด์ที่สะท้อนฟิลด์ของคลาสหลัก แต่ละ set-เมธอดส่งคืน Builder (this) สำหรับการโยงแบบลื่นไหล เมธอด build() สุดท้ายสร้างวัตถุเป้าหมายโดยส่งค่าฟิลด์ไปยังคอนสตรักเตอร์ส่วนตัว คลาสหลักมีคอนสตรักเตอร์ส่วนตัวที่รับ Builder ไคลเอ็นต์: Object.builder().setField1(val1).setField2(val2).build()

เมื่อใดควรใช้ Builder — วัตถุที่มี 5+ ฟิลด์โดยมีเพียง 2-3 ฟิลด์ที่จำเป็น วัตถุการกำหนดค่า (RequestConfig, DatabaseConfig) วัตถุที่มีตรรกะการตรวจสอบที่ซับซ้อนระหว่างการสร้าง วัตถุที่ต้องไม่เปลี่ยนแปล (immutable) หลังจากการสร้าง ใน Android Builder ถูกใช้อย่างแข็งขันใน SDK: AlertDialog.Builder, Retrofit.Builder, OkHttpClient.Builder, NotificationCompat.Builder

Builder ใน Kotlin: การใช้งานแบบคลาสสิกและ DSL

Builder ใน Kotlin มีสองแนวทาง: Builder แบบ Java คลาสสิก (ผ่านคลาสที่ซ้อนกัน) และ DSL builder แบบ Kotlin (ผ่านแลมบ์ดากับตัวรับ) Builder แบบ Java เหมาะสำหรับความเข้ากันได้กับ Android และเมื่อใช้กับโค้ด Java DSL builder เป็นวิธีธรรมชาติของ Kotlin: ฟังก์ชันรับแลมบ์ดาซึ่งภายใน this คือบริบท Builder ที่สามารถกำหนดฟิลด์ได้โดยตรง

kotlin
// 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)
        }
    }
}

// การใช้งาน
val config = HttpConfig.Builder()
    .baseUrl("https://api.example.com")
    .timeout(15_000)
    .header("Authorization", "Bearer token")
    .build()

Kotlin DSL builder — ทางเลือกที่ไม่มีคลาสซ้อนกัน ฟังก์ชัน builder รับแลมบ์ดาในบริบทของวัตถุผู้สร้าง ซึ่งเป็นธรรมชาติสำหรับ Kotlin และไม่ต้องใช้ฟิลด์ write DSL builders ถูกใช้อย่างแข็งขันใน Ktor Client, kotlinx.serialization, Compose (Modifier) DSL builder ไม่เข้ากันได้กับ Java และไม่เหมาะสำหรับไลบรารีที่มี Java API

Builder ใน Swift: result builders และลูกโซ่

Builder ใน Swift — Swift ไม่มีรูปแบบ Builder ในตัว แต่อินเทอร์เฟซที่ลื่นไหลสามารถใช้งานได้ง่ายผ่านเมธอดที่ส่งคืน Self แต่ละเมธอดกำหนดค่าคุณสมบัติและส่งคืน self แตกต่างจาก Kotlin, Swift ไม่ต้องการคลาส Builder แยกต่างหาก — คุณสามารถส่งคืนวัตถุนั้นได้เองหากสามารถเปลี่ยนแปลงได้ระหว่างการประกอบ สำหรับวัตถุที่ไม่เปลี่ยนแปล จะใช้คลาส Builder ที่ซ้อนกันเช่นเดียวกับ Kotlin

swift
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 — กลไกภาษาเพื่อการสร้างโครงสร้างแบบประกาศ SwiftUI, AttributedString, SceneBuilder ใช้ result builders นี่เป็นทางเลือกแทน Builder แบบคลาสสิก: แทนที่จะเป็นลูกโซ่ของ set-เมธอด result builder ใช้บล็อคโค้ดที่มีองค์ประกอบที่คอมไพเลอร์ประกอบเป็นอาร์เรย์หรือต้นไม้ @ViewBuilder ใน SwiftUI เป็นตัวอย่างที่รู้จักกันดีที่สุด: ภายใน body สามารถเขียน if, switch, ForEach และคอมไพเลอร์สร้าง View จากเงื่อนไข

Builder vs Telescoping Constructor: การเปรียบเทียบแนวทาง

Telescoping Constructor — ปฏิรูปที่คลาสมีคอนสตรักเตอร์ที่โอเวอร์โหลดหลายตัวพร้อมชุดพารามิเตอร์ที่แตกต่างกัน ตัวอย่างเช่น สามคอนสตรักเตอร์: HttpConfig(url), HttpConfig(url, timeout), HttpConfig(url, timeout, retries) เมื่อพารามิเตอร์เพิ่มขึ้น จำนวนคอนสตรักเตอร์เพิ่มขึ้นแบบทวีคูณ — สำหรับ n ฟิลด์เลือกได้ ต้องการ n! ชุดค่าผสม Builder แก้ปัญหานี้โดยอนุญาตให้ระบุเฉพาะฟิลด์ที่จำเป็น

คุณลักษณะTelescoping ConstructorBuilderKotlin named args
ปริมาณโค้ดเพิ่มขึ้นแบบทวีคูณเพิ่มขึ้นเชิงเส้นน้อยที่สุด
ความอ่านง่ายต่ำ (พารามิเตอร์ไหนคืออะไร?)สูง (เมธอด + ชื่อ)สูง (ชื่อ = ค่า)
ความไม่เปลี่ยนแปลงไม่เปลี่ยนแปลไม่เปลี่ยนแปลไม่เปลี่ยนแปล
ความเข้ากันได้กับ Javaเต็มเต็มไม่มี (เฉพาะ Kotlin)
การตรวจสอบในแต่ละคอนสตรักเตอร์ใน build() — ครั้งเดียวใน init()

Kotlin named arguments + ค่าเริ่มต้น — ทางเลือกที่หรูหราสำหรับ Builder ในโปรเจกต์ Kotlin บริสุทธิ์ พารามิเตอร์ของคอนสตรักเตอร์มีค่าเริ่มต้น ไคลเอ็นต์ส่งเฉพาะที่จำเป็น: HttpConfig(baseUrl = url, timeout = 15_000) ข้อเสียคือไม่สามารถตรวจสอบฟิลด์ที่จำเป็นในเวลาคอมไพล์ Builder ให้ฟิลด์ที่จำเป็นผ่านคอนสตรักเตอร์ของ Builder (baseUrl จำเป็น) สำหรับไลบรารี Java Builder ยังคงเป็นมาตรฐานโดยพฤตินัย

Builder ใน Android SDK: AlertDialog, Retrofit, OkHttp

Builder ใน Android SDK — หนึ่งในรูปแบบที่พบบ่อยที่สุดในไลบรารีมาตรฐาน 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 จึงใช้ Builder — ความเข้ากันได้ย้อนหลัง การเพิ่มเมธอดใหม่ใน Builder ไม่ทำลายโค้ดที่มีอยู่ ถ้า Google ใช้คอนสตรักเตอร์ที่มี 20 พารามิเตอร์ แต่ละฟิลด์ใหม่จะต้องมีการโอเวอร์โหลดใหม่ Builder อนุญาตให้เพิ่ม set-เมธอดเป็นเวลาหลายปีโดยไม่มีการเปลี่ยนแปลงที่ทำลาย ตัวอย่างเช่น NotificationCompat.Builder เพิ่ม setBubbleMetadata() ใน Android 11 โดยไม่ส่งผลกระทบต่อโค้ดที่มีอยู่

Builder ในไลบรารี Kotlin — Ktor (HttpClientBuilder), Coil (ImageRequest.Builder), Room (Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build()), Navigation (NavOptionsBuilder) ในโปรเจกต์ Kotlin Builder มักถูกรวมกับ DSL: Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build() รูปแบบนี้ยังคงเกี่ยวข้องสำหรับ API สาธารณะที่ความเข้ากันได้ย้อนหลังและการทำงานร่วมกับ Java มีความสำคัญ

คำถามที่พบบ่อย

เมื่อใดที่ Builder มากเกินไป?

Builder มากเกินไปสำหรับวัตถุที่มี 1-3 ฟิลด์ — คอนสตรักเตอร์ปกติหรือ data class ชัดเจนกว่า นอกจากนี้ยังมากเกินไปในโปรเจกต์ Kotlin ที่ไม่มีการทำงานร่วมกับ Java ซึ่ง named arguments + ค่าเริ่มต้นแก้ปัญหาเดียวกันได้ง่ายกว่า Builder เหมาะสมสำหรับ 5+ ฟิลด์ การตรวจสอบที่ซับซ้อน หรือ Java API ที่ไม่มี named arguments

Builder แตกต่างจาก Factory อย่างไร?

Builder สร้างวัตถุที่ซับซ้อนหนึ่งชิ้นทีละขั้นตอน (การกำหนดค่าฟิลด์) Factory สร้างวัตถุทั้งหมดตามประเภทหรือพารามิเตอร์ Builder ตอบคำถาม «ประกอบอย่างไร?» Factory ตอบ «สร้างอะไร?» Builder มักจะรวมกับ Factory: Factory เลือกประเภท Builder กำหนดค่าฟิลด์

จำเป็นต้องใช้ Builder ใน SwiftUI หรือไม่?

ใน SwiftUI บทบาทของ Builder ดำเนินการโดย result builders (@ViewBuilder, @SceneBuilder) และตัวปรับแต่ง View (.font(), .padding()) ไม่จำเป็นต้องใช้ Builder แบบคลาสสิกเพราะ SwiftUI ใช้แนวทางการประกาศและตัวปรับแต่งที่ลื่นไหล สำหรับส่วนประกอบ UIKit Builder มีประโยชน์: UIAlertController, URLRequest, NSAttributedString

จะทำให้ Builder ปลอดภัยสำหรับเธรดได้อย่างไร?

Builder โดยทั่วไปไม่ต้องการความปลอดภัยของเธรดเนื่องจากใช้ในเธรดเดียวเพื่อประกอบวัตถุ ถ้า Builder ถูกใช้ในสภาพแวดล้อมแบบหลายเธรด (กรณียาก) ให้ซิงโครไนซ์แต่ละ set-เมธอดและ build() ทางเลือก — Immutable Builder: แต่ละ set-เมธอดส่งคืนอินสแตนซ์ Builder ใหม่พร้อมฟิลด์ที่ถูกแก้ไข

เหตุใด Retrofit ใช้ Builder แทน DI?

Retrofit.Builder เป็น API ไลบรารีสาธารณะที่ต้องทำงานโดยไม่มีคอนเทนเนอร์ DI Builder ให้ความยืดหยุ่นในการกำหนดค่า (baseUrl ตัวแปลง ตัวสกัดกั้น ตัวปรับแต่งการเรียก) โดยไม่ต้องพึ่งพา Dagger หรือเฟรมเวิร์ก DI อื่น ๆ ภายในแอปพลิเคชัน DI สามารถสร้าง Retrofit ครั้งเดียวผ่าน Builder แต่ Builder เองยังคงเป็นส่วนหนึ่งของ API สาธารณะของ Retrofit

สรุป

  • Builder — การสร้างวัตถุทีละขั้นตอนด้วยอินเทอร์เฟซที่ลื่นไหล
  • Kotlin Builder — คลาสสิก (คลาสซ้อนกัน) และ DSL (แลมบ์ดากับตัวรับ)
  • Swift Builder — คลาสซ้อนกันหรือ @resultBuilder สำหรับโค้ดแบบประกาศ
  • ความไม่เปลี่ยนแปลง — Builder สร้างวัตถุที่ไม่เปลี่ยนแปลผ่านคอนสตรักเตอร์ส่วนตัว
  • Android SDK — AlertDialog, Retrofit, OkHttp, NotificationCompat — มาตรฐานอุตสาหกรรม
  • ความเข้ากันได้ย้อนหลัง — การเพิ่มฟิลด์ใน Builder ไม่ทำลายโค้ดที่มีอยู่
  • ทางเลือก Kotlin — named arguments + ค่าเริ่มต้นง่ายกว่าสำหรับโปรเจกต์ Kotlin บริสุทธิ์

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม