Интерфейс

Интерфейс

Интерфейсы играют роль требования к классу. Все обязательные члены в интерфейсе

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

В интерфейсах функции могут быть абстрактными (не иметь тела) или иметь код, который выполняется если в классе функция не переписана.

Свойства в интерфейсах либо должны быть абстрактными, либо для них должны быть определены функции доступа (getter и setter). В отличии от классов в свойствах в интерфейсах нет доступа к его значению посредством ключевого слова field.

interface MyInterface {
    // Для обычных переменных указывается только название и тип
    var prop : Int

    // Можно указать значение, если переменная только для чтения
    val prop2 : String get() = "Property 2"

    // Абстрактная функция не имеет тела
    fun test()

    // Абстрактная функция принимающая аргументы и которая должна вернуть значение типа String
    fun test(param : String, param2 : Int) : String

    // Код функции выполняется когда эта функция не переписана в классе.
    fun second() {
        println("Function code is not written")
    }
}

Если класс применяет только интерфейс и не наследует другой класс, тогда название интерфейса пишется через двоеточие - :, когда класс применяет более одного интерфейса или также является производным классом наряду с применением интерфейса тогда разделителем является запятая.

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

class MainActivity : AppCompatActivity(), MyInterface {
    // Переписывание свойства из примененного интерфейса
    override var prop: Int = 0
        get() = field
        set(value) {
            field = value
        }

    // Код для выполнения при вызове функции test, так как функция не имеет поведение по умолчанию
    override fun test() {}

    // Код перегруженной версии функции test, которая принимает два параметра и возвращает результат строкового типа
    override fun test(param: String, param2: Int): String {
        return "Test"
    }

    // Переписывание функции second необязательна так как она имеет поведение по умолчанию, но по необходимости можно переписать

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

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

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

В случае добавления ещё одного интерфейса в наш пример со свойством isActive, который наследует интерфейс MyInterface и применить его, то в данном случае в классе необходимо переписать как обязательные члены первого интерфейса, так и второго, так как второму они становятся доступны "по наследству":

interface SecondInterface : MyInterface {
    var isActive : Boolean
}

class MainActivity : AppCompatActivity(), SecondInterface {
    override var isActive: Boolean = false

    // Переписывание свойства из примененного интерфейса
    override var prop: Int = 0
        get() = field
        set(value) {
            field = value
        }

    // Код для выполнения при вызове функции test, так как функция не имеет поведение по умолчанию
    override fun test() {}

    // Код перегруженной версии функции test, которая принимает два параметра и возвращает результат строкового типа
    override fun test(param: String, param2: Int): String {
        return ""
    }

    // Переписывание функции second необязательна так как она имеет поведение по умолчанию

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}