Интерфейсы

Интерфейсы в Kotlin очень похожи на Java 8. Они могут содержать объявление абстрактных методов, а также реализации методов. Что отличает их от абстрактных классов, так это то, что интерфейсы не могут хранить состояние. У интерфейсов могут быть свойства, но они должны быть абстрактными или предоставлять реализацию аксессоров.

Интерфейс в Kotlin языке определяется с использованием ключевого слова interface

interface MyInterface {
    fun bar()
    fun foo() {
      // тело функции опционально
    }
}

Реализация интерфейсов

Класс или объект может реализовать один или несколько интерфейсов

class Child : MyInterface {
    override fun bar() {
        // тело функции
    }
}

Свойства в интерфейсах

Вы можете объявлять свойства в интерфейсах. Свойство объявленое в интерфейсе может быть либо абстрактным, либо предоставлять реализацию для аксессоров. Свойстваа объявленные в интерфейсах не могут иметь backing полей, поэтому аксессор методы не могут ссылаться на них.

interface MyInterface {
    val prop: Int // абстрактное

    val propertyWithImplementation: String
        get() = "foo"

    fun foo() {
        print(prop)
    }
}

class Child : MyInterface {
    override val prop: Int = 29
}

Наследование интерфейсов

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

interface Named {
    val name: String
}

interface Person : Named {
    val firstName: String
    val lastName: String

    override val name: String get() = "$firstName $lastName"
}

data class Employee(
    // реализация 'name' не обязательна
    override val firstName: String,
    override val lastName: String,
    val position: Position
) : Person

Разрешение конфликтов переопределения

Когда мы объявляем много типов в нашем списке супертипов, может показаться, что мы наследуем более одной реализации того же метода как показано на примере ниже:

interface A {
    fun foo() { print("A") }
    fun bar()
}

interface B {
    fun foo() { print("B") }
    fun bar() { print("bar") }
}

class C : A {
    override fun bar() { print("bar") }
}

class D : A, B {
    override fun foo() {
        super<A>.foo()
        super<B>.foo()
    }

    override fun bar() {
        super<B>.bar()
    }
}

Интерефейсы A и B оба объяляют функции foo() и bar(). Оба интерфейса реализуют foo(), но только B реализуется foo() и bar() (bar() не помечен абстрактным в A, потому что это является по умолчанию для интерфейсов, если функция не имеет тела). Теперь, если мы наследуем конкретный класс C от A, очевидно мы должны переопределить bar() и предоставить реализацию.

Однако, если мы наследуем D от A и B, мы должны реализовать все метды нескольких интерфейсов и указать как именно D будет их реализовать. Это правило в Kotlin применяется как к функциям унаследованным с одной реализацией, так и к фукнциям со множественной реализацией.

Комментарии

Популярные сообщения из этого блога

Псевдонимы типов

Идиомы

Базовый синтаксис