Pola Builder
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Kotlin di Coddy. Pelajaran 48 dari 57.
Pola builder membuat object secara bertahap dan memeriksa seluruhnya pada bagian akhir. Builder mengumpulkan bagian-bagiannya melalui method berantai yang mengembalikan builder itu sendiri, lalu build() membuat object yang sudah selesai:
data class Email(val to: List<String>, val subject: String)
class EmailBuilder {
private val recipients = mutableListOf<String>()
private var subject = ""
fun to(address: String): EmailBuilder {
recipients.add(address)
return this
}
fun subject(text: String): EmailBuilder {
subject = text
return this
}
fun build(): Email {
check(recipients.isNotEmpty()) { "no recipients" }
return Email(recipients.toList(), subject)
}
}Di dalam main:
val mail = EmailBuilder().to("ada@x.io").to("bo@x.io").subject("Lunch").build()
println(mail)Output:
Email(to=[ada@x.io, bo@x.io], subject=Lunch)apply mempersingkat setiap langkah: fungsi ini menjalankan blok dengan object sebagai this dan mengembalikan object tersebut, sehingga satu langkah menjadi satu baris. check(condition) { message } melempar IllegalStateException, padanan require untuk keadaan object:
class RequestBuilder {
var url = ""
var method = "GET"
private val headers = mutableListOf<String>()
fun header(name: String, value: String) = apply { headers.add("$name: $value") }
fun build(): String {
check(url.isNotEmpty()) { "no url" }
return "$method $url " + headers
}
}Di dalam main:
val request = RequestBuilder().apply {
url = "/users"
method = "POST"
header("Accept", "json")
}.build()
println(request)Output:
POST /users [Accept: json]Fungsi yang menerima lambda dengan receiver, bertipe Builder.() -> Unit, mengubah builder menjadi DSL kecil (bahasa khusus domain): di dalam kurung kurawal, builder menjadi this, jadi pemanggil hanya menulis konfigurasi:
class MenuBuilder(private val title: String) {
private val items = mutableListOf<String>()
fun item(name: String, cents: Int) {
items.add("$name %d.%02d".format(cents / 100, cents % 100))
}
fun build() = "== $title ==\n" + items.joinToString("\n")
}
fun menu(title: String, block: MenuBuilder.() -> Unit): String = MenuBuilder(title).apply(block).build()Di dalam main:
val lunch = menu("Lunch") {
item("soup", 450)
item("salad", 600)
}
println(lunch)Output:
== Lunch ==
soup 4.50
salad 6.00Argumen bernama dan default Kotlin sudah mencakup kasus sederhana: Pizza(size = 30, cheese = true) memberi nama pada setiap pilihan saat pemanggilan. Builder berguna saat object dirakit dalam beberapa langkah, mengumpulkan list, atau memerlukan pemeriksaan antarbidang sebelum dapat dibuat:
data class Pizza(val size: Int = 26, val cheese: Boolean = true, val olives: Boolean = false)
val simple = Pizza(size = 30, olives = true) // tidak perlu builder
val mail = EmailBuilder() // builder untuk menyusun secara bertahap
.to("ada@x.io")
.to("bo@x.io") // mengumpulkan nilai dalam list
.subject("Plan")
.build() // memeriksa semuanya di akhirTantangan
MudahTulis builder untuk data class Email yang disediakan. EmailBuilder memiliki langkah-langkah berantai: to(address) (dapat dipanggil beberapa kali dan menambahkan penerima), subject(text), body(text), dan urgent(). build() mengembalikan Email atau melempar IllegalStateException dengan no recipients atau no subject (sesuai urutan pemeriksaan tersebut). Email yang mendesak akan mendapat [URGENT] di depan subject-nya.
Kode yang disediakan membaca perintah (to ada@x.io, subject Hello, body text, urgent, send), memulai builder baru setelah setiap baris ---, lalu mencetak email yang dibuat, To: ada@x.io, bo@x.io | [URGENT] Hello | text, atau error: no subject.
Kodemu ditulis di EmailBuilder.kt dan Email.kt. Main.kt berisi kode input/output yang disediakan dan tidak boleh diedit.
Coba sendiri
fun main() {
// Kode input/output yang disediakan: biarkan tetap seperti ini
val input = generateSequence(::readLine).toList()
var builder = EmailBuilder()
for (cmd in input) {
when {
cmd == "send" -> {
try {
println(builder.build())
} catch (e: IllegalStateException) {
println("error: ${e.message}")
}
}
cmd == "---" -> builder = EmailBuilder()
cmd == "urgent" -> builder.urgent()
cmd.startsWith("to ") -> builder.to(cmd.drop(3))
cmd.startsWith("subject ") -> builder.subject(cmd.drop(8))
else -> builder.body(cmd.drop(5))
}
}
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1class dan object
Bekerja dengan fileMendefinisikan classKonstruktor utamaBlok init dan validasiKonstruktor sekunderRingkasan: Kartu Perpustakaan2property dan Enkapsulasi
Accessor KustomModifier VisibilitasSetter Privatlazy dan lateinitRingkasan: Rekening Bank5Interface
Mendeklarasikan Interfacemethod DefaultBeberapa InterfaceInterface sebagai TipeUlasan: Metode Pembayaran11Proyek: Pengelolaan Perpustakaan
Buku dan AnggotaPeminjaman BukuLatihan sendiri: Playground Kotlin