Как реализовать Singleton в Kotlin

Ответ

object Singleton {
    fun doSomething() {
        println("Doing something...")
    }
}

В Kotlin Singleton реализуется через ключевое слово object. Это обеспечивает:

  1. Потокобезопасную инициализацию
  2. Ленивую загрузку (инициализируется при первом доступе)
  3. Автоматическую реализацию шаблона Singleton

Доступ к Singleton:

Singleton.doSomething()

Альтернатива с конструктором (если нужна кастомизация):

class Singleton private constructor() {
    companion object {
        @Volatile private var instance: Singleton? = null

        fun getInstance(): Singleton {
            return instance ?: synchronized(this) {
                instance ?: Singleton().also { instance = it }
            }
        }
    }
}

Ответ 18+ 🔞

А, слушай, вот эта штука с синглтонами — это вообще отдельная песня, ебать мои старые костыли. Все эти паттерны, а в Котлине всё уже придумали за нас, ленивых.

Вот смотри, если по-простому, то там вообще пиздец как легко. Вместо того чтобы городить огород с приватным конструктором и статическим методом, как в том самом джаве, который уже накрылся медным тазом, тут просто пишешь одно слово: object. И всё, ёпта. Готово.

object Singleton {
    fun doSomething() {
        println("Doing something...")
    }
}

Вот и весь сказ. А под капотом-то, чувак, магия происходит: потокобезопасная инициализация, ленивая загрузка — то есть этот объект создаётся только тогда, когда ты к нему первый раз обратился, а не при старте программы. И никаких тебе танцев с бубном. Просто Singleton.doSomething() и поехали. Удивление пиздец, как же это удобно.

Но, конечно, бывают хитрожопые ситуации. Ну там, если тебе надо как-то кастомизировать создание, передать какие-то параметры, или ещё какая-то мудя. Тогда да, придётся вспомнить старую школу и написать этот классический, блядь, шаблон с двойной проверкой. Выглядит, конечно, как залупа конская, но работает.

class Singleton private constructor() {
    companion object {
        @Volatile private var instance: Singleton? = null

        fun getInstance(): Singleton {
            return instance ?: synchronized(this) {
                instance ?: Singleton().also { instance = it }
            }
        }
    }
}

Смотришь на это и думаешь: «Какого хуя? Зачем?» Но иногда без этого никак, если логика инициализации нестандартная. Хотя в 95% случаев тебе хватит обычного object, и не надо выёбываться. Чёрта в душу, зачем усложнять, если можно просто?