Приведи пример порождающего паттерна

Ответ

Singleton — гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к нему.

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

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

Использование:

val singleton = Singleton.getInstance()

Плюсы:

  • Контроль доступа к единственному экземпляру.
  • Ленивая инициализация (экземпляр создаётся только при первом вызове).

Минусы:

  • Усложняет тестирование из-за глобального состояния.
  • Нарушает принцип единственной ответственности.

Ответ 18+ 🔞

Давай разберем эту вашу одинокую сущность, этот паттерн Singleton. Представь себе, что ты — единственный унитаз на весь офисный этаж. Все ходят к тебе, ты всем нужен, и ты должен быть один. Вот это и есть Синглтон, ёпта.

Вот смотри, как это выглядит в коде, прям классика жанра:

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

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

Что тут происходит, ядрёна вошь? private constructor() — это чтобы всякие умники не лезли со своими new Singleton(). Хуй с горы, а не публичный конструктор! Создать экземпляр можно только через getInstance(). А внутри — вся эта синхронизация и проверка @Volatile, чтобы в многопоточке не вышло, что два потока одновременно создадут два экземпляра. Это как если бы два человека вломились в единственную кабинку — пиздопроебибна получится, а не работа.

Как этим пользоваться? Да элементарно!

val singleton = Singleton.getInstance()

Всё. Больше нигде не new, нигде не создаём. Берём один готовый экземпляр и таскаем его по всему приложению, как чемодан без ручки.

Ну и что он нам дает, этот самый Синглтон?

  • Контроль доступа к единственному экземпляру. Ты точно знаешь, что этот объект в единственном числе, как последняя пельмешка в тарелке. Все изменения в нём видны отовсюду.
  • Ленивая инициализация. Объект создастся не когда приложение стартанёт, а только когда кто-то первый раз лениво скажет «дай-ка я его получу». Пока не спросили — живи спокойно, ресурсы не жри.

А теперь минусы, и они овердохуища серьёзные:

  • Тестирование превращается в ад. Потому что этот объект — глобальное состояние. Протестировал ты его в одном тесте, он поменялся, а следующий тест уже на подпорченных данных работает. Доверия ебать ноль к результатам таких тестов.
  • Нарушает принцип единственной ответственности. Класс начинает заниматься не только своей прямой работой, но и ебётся с контролем над своим жизненным циклом. Это как если бы унитаз сам решал, когда его чистить. Мудя полная.
  • Скрытая зависимость. Классы, которые используют синглтон, не объявляют эту зависимость явно в конструкторе. Она просто берётся из воздуха. Подозрение ебать чувствую к такому коду.

Короче, паттерн как будто простой, но вы ходите по охуенно тонкому льду. Часто его используют там, где можно было бы обойтись нормальной зависимостью через DI-контейнер. Используй с умом, а то получится хитрая жопа, которую потом год распутывать.