Menu
CoddyTech

Pola Singleton

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Kotlin di Coddy. Pelajaran 42 dari 57.

design pattern adalah solusi teruji untuk masalah desain yang berulang kali muncul. Pola singleton memastikan sebuah class memiliki tepat satu instance yang dapat diakses oleh seluruh program. Di Kotlin, deklarasi object adalah singleton: deklarasi ini dibuat sekali, saat pertama kali digunakan, dan tetap aman meskipun beberapa thread dimulai pada saat yang sama:

object Settings {
    var theme = "light"
    var fontSize = 14
}

fun openEditor() = "editor in ${Settings.theme} theme"

Di dalam main:

Settings.theme = "dark"
println(openEditor())
println(Settings.fontSize)

Output:

editor in dark theme
14

Singleton menyimpan state yang digunakan bersama oleh berbagai bagian program. Jaga state tersebut tetap privat dan ubah hanya melalui method, sehingga setiap perubahan mengikuti aturan yang sama:

object Metrics {
    private val hits = mutableMapOf<String, Int>()

    fun hit(page: String) { hits[page] = (hits[page] ?: 0) + 1 }
    fun report() = hits.entries.joinToString { "${it.key}=${it.value}" }
}

fun home() = Metrics.hit("home")
fun about() = Metrics.hit("about")

Di dalam main:

home(); about(); home()
println(Metrics.report())

Output:

home=2, about=1

Saat instance tunggal memerlukan data penyiapan, class dengan private constructor dapat membuatnya di companion object pada permintaan pertama, lalu mengembalikan instance yang sama pada permintaan berikutnya:

class Database private constructor(val url: String) {
    companion object {
        private var instance: Database? = null

        fun connect(url: String): Database =
            instance ?: Database(url).also { instance = it }
    }
}

Di dalam main:

val a = Database.connect("db://main")
val b = Database.connect("db://other")
println(a === b)
println(b.url)

Output:

true
db://main

Gunakan singleton secukupnya. Singleton adalah state global: kode apa pun dapat mengubahnya, sehingga tidak jelas siapa yang bergantung padanya, dan pengujian tidak dapat dimulai dari salinan yang baru. Singleton cocok untuk hal yang memang hanya ada satu per program, seperti konfigurasi atau logger. Jika hanya sebagian program yang membutuhkan object, berikan object itu sebagai parameter dengan tipe interface, sehingga pengujian dapat memberikan object palsu sebagai gantinya:

interface Clock { fun now(): Long }
object SystemClock : Clock { override fun now() = System.currentTimeMillis() }

class Session(private val clock: Clock) {      // dependensinya terlihat
    val started = clock.now()
}
val session = Session(SystemClock)             // pengujian meneruskan Clock palsu
challenge icon

Tantangan

Mudah

Lengkapi singleton Logger. Singleton ini memiliki minLevel yang bisa diubah (debug, info, warn, atau error, dalam urutan tersebut). log(level, message) menyimpan [WARN] disk low jika levelnya setidaknya minLevel. Jika tidak, fungsi ini menghitung pesan tersebut dalam dropped, yang bisa dibaca tetapi tidak bisa diubah dari luar kode. entries adalah list hanya-baca yang berisi baris tersimpan, dan count(level) mengembalikan jumlah baris tersimpan dengan level tersebut.

Fungsi helper dalam Functions.kt sudah disediakan: fungsi-fungsi tersebut mengakses Logger yang sama dari file lain. Kode yang disediakan membaca level minimum, lalu baris dengan format level,message, kemudian mencetak setiap entri dan errors: 1, dropped: 2.

Tulis kodemu di Logger.kt dan Functions.kt. Main.kt berisi kode input/output yang disediakan dan tidak boleh diedit.

Coba sendiri

fun main() {
    // Kode input/output yang disediakan: biarkan apa adanya
    val input = generateSequence(::readLine).toList()
    Logger.minLevel = input[0]
    for (line in input.drop(1)) {
        val (level, message) = line.split(",", limit = 2)
        when (level) {
            "debug" -> debug(message)
            "info" -> info(message)
            "warn" -> warn(message)
            else -> error(message)
        }
    }
    for (e in Logger.entries) println(e)
    println("errors: ${Logger.count("error")}, dropped: ${Logger.dropped}")
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Playground Kotlin