Menu
Coddy logo textTech

Объектные выражения

Часть раздела Объектно-ориентированное программирование путешествия по Kotlin на Coddy. Урок 15 из 57.

Выражение объекта создаёт одноразовый объект безымянного класса именно там, где он нужен. Оно записывается как object : Type { ... } и обычно реализует интерфейс. Интерфейс перечисляет методы, не объясняя, как они работают; интерфейсы подробно рассматриваются в главе 5:

interface Greeter {
    fun greet(name: String): String
}

Внутри main:

val polite = object : Greeter {
    override fun greet(name: String) = "Good morning, $name."
}
println(polite.greet("Ada"))

Результат:

Good morning, Ada.

Объявление объекта существует в единственном экземпляре. Выражение объекта вычисляется каждый раз, когда выполняется его код, и при каждом выполнении создаётся новый объект. Оно может читать локальные переменные вокруг себя и изменять их:

interface Counter {
    fun next(): Int
}

fun counterFrom(start: Int): Counter {
    var current = start
    return object : Counter {
        override fun next() = current++
    }
}

Внутри main:

val a = counterFrom(10)
val b = counterFrom(1)
println("${a.next()} ${a.next()} ${b.next()}")

Результат:

10 11 1

Один из распространённых вариантов использования — передать поведение функции библиотеки. sortedWith принимает Comparator — интерфейс, метод которого compare(a, b) возвращает отрицательное число, когда a должно идти первым, ноль при равенстве и положительное число в остальных случаях:

Внутри main:

val words = listOf("kiwi", "fig", "banana", "apple")
val byLength = object : Comparator<String> {
    override fun compare(a: String, b: String) = a.length - b.length
}
println(words.sortedWith(byLength))

Вывод:

[fig, kiwi, apple, banana]

Объектное выражение без надтипа объединяет несколько значений в локальный объект; его свойства можно использовать внутри той же функции. Если у интерфейса есть единственный метод, лямбда часто короче объектного выражения. Объектные выражения подходят, когда есть несколько методов или требуется сохранить некоторое состояние.

val size = object {
    val width = 3
    val height = 4
}
println(size.width * size.height)                    // 12

val byLength = Comparator<String> { a, b -> a.length - b.length }   // лямбда-форма
challenge icon

Задание

Легко

Интерфейс Validator имеет один метод — check(text), который возвращает сообщение об ошибке или null, когда текст проходит проверку. Дополните функцию rules(minLength), чтобы она возвращала три валидатора, созданных с помощью объектных выражений, в следующем порядке: текст должен содержать как минимум minLength символов (too short), содержать цифру (needs a digit) и не содержать пробелов (no spaces allowed).

Предоставленный код считывает минимальную длину, а затем по одному паролю в каждой строке. Он выводит ok или все сообщения об ошибках этого пароля, объединённые с помощью ; .

Ваш код должен находиться в Rules.kt и Validator.kt. В Main.kt находится предоставленный код ввода/вывода, и его нельзя изменять.

Попробуйте сами

fun main() {
    // Предоставленный код ввода/вывода: оставьте его как есть
    val input = generateSequence(::readLine).toList()
    val checks = rules(input[0].toInt())
    for (password in input.drop(1)) {
        val problems = checks.mapNotNull { it.check(password) }
        println(if (problems.isEmpty()) "ok" else problems.joinToString("; "))
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Песочница Kotlin