_Первоначальная настройка — InterfacesStarter_

давайте создадим файл main.kt

```

- В main.kt

```

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

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

```

- Интерфейсы

- Укажите контракты, указав методы, которые должны реализовать другие классы.

```

Интерфейс содержит функции, но фактически не реализует эти функции. На самом деле интерфейсы содержат только сигнатуры функций. Сигнатура функции — это, по сути, имя функции, ее аргументы и тип возвращаемого значения.

Итак, теперь давайте продолжим и создадим такой интерфейс:

_Демо_

```

- Создать файл интерфейса › IStaff

```

Теперь давайте определим две сигнатуры функций в этом интерфейсе:

_Демо — IStaff.kt_

```

интерфейс IStaff {

весело simpleGreeting(): Строка

fun advancedGreeting(name: String): String

}

```

Теперь, как вы видите, я определил две функции, но не дал их реализации. Первая — это простая функция приветствия, а вторая — расширенная функция приветствия.

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

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

А пока давайте создадим новое предложение, которое будет реализовывать методы этого интерфейса.

_Демо_

```

- Создать новый класс › Администратор

```

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

_Демо — Receptionist.kt_

```

секретарь класса: IStaff {

}

```

Теперь давайте воспользуемся контекстным действием для реализации методов интерфейса I нотоносца:

_Демо — Receptionist.kt_

```

- Контекстное действие › Внедрение членов IStaff

```

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

Итак, теперь он возвращает разные строки из двух функций:

_Демо — Receptionist.kt_

```

- Определить функцию simpleGreeting:

return «Регистратор: Доброе утро!»

- Определить функцию advancedGreeting:

return «Регистратор: Доброе утро, $name! Менеджер в офисе».

```

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

```

- Еще один класс для реализации интерфейса IStaff.

```

_Демо_

```

- Создать новый класс файлового менеджера и внедрить IStaff

Менеджер класса: IStaff {

}

```

Теперь для этого класса мы собираемся изменить реализации методов простого приветствия и расширенного приветствия.

_Демо — Manager.kt_

```

- Определить функцию simpleGreeting:

вернуть «Менеджер:

Привет! Я управляющий».

- Определить функцию advancedGreeting:

вернуть «Менеджер:

Доброе утро $имя. Я ждал тебя. Итак, как прошла поездка из Оттавы?

```

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

Итак, теперь давайте переключимся на основной файл и проверим интерфейс.

_Демо — main.kt_

```

- Переключиться на main.kt

```

А теперь давайте создадим переменную типа interface staff, которая будет содержать объект класса администратора.

_Демо — main.kt_

```

var staff: IStaff = Администратор()

```

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

Например, в этом случае класс администратора реализует интерфейс Istaff, поэтому мы можем хранить объект типа администратора в переменной staff.

Далее давайте вызовем расширенную функцию приветствия для объекта персонала. Обратите внимание, что объект, хранящийся внутри персонала, является экземпляром класса администратора.

_Демо — main.kt_

```

println(staff.advancedGreeting("Дэйв"))

```

И запустим основную функцию:

_Демо — main.kt_

```

- Запустить основной

```

И взгляните на это: реализована реализация расширенной функции приветствия в классах администратора.

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

_Демо — main.kt_

```

персонал = менеджер ()

println(staff.advancedGreeting("Дэйв"))

```

Запускаем основную функцию:

_Демо — main.kt_

```

- Запустить основной

```

И взгляните на это. На этот раз была выполнена расширенная реализация функций приветствия, определенная в классе менеджера.

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

Но какая именно от этого польза. преимущество в том, что мы можем создавать слабосвязанные программы. Теперь, что это значит. Что ж, лучший способ понять, что означает это утверждение, — это воспользоваться примером. Итак, давайте посмотрим на один.

```

- Внедрение зависимости

- Основной пример

```

Сначала давайте создадим новый класс с именем Meeting следующим образом:

_Демо — main.kt_

```

- Создать классную встречу

собрание класса {

}

```

Далее меньше определите конструктор для класса встречи:

_Демо — main.kt_

```

Собрание класса (частный val staff: IStaff, private val name: String) {…}

```

И взгляните на этот конструктор. Конструктор принимает два аргумента, что означает, что он определяет переменные экземпляра. Первая — это переменная, которая может содержать реализацию интерфейса персонала. вторая переменная экземпляра — это просто строка, представляющая чье-то имя.

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

Я уточню этот момент через несколько минут. А пока давайте определим метод приветствия следующим образом:

```

- Передать ссылку на интерфейс в конструкторе

- Создайте переменную, в которой будет храниться любой класс, реализующий IStaff

```

_Демо — main.kt_

```

- Внутри основного класса

веселое приветствие(): строка {

return staff.advancedGreeting(имя)

}

```

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

А теперь попробуем что-нибудь интересное. Сначала давайте создадим цикл for в функции main:

_Демо — main.kt_

```

- Внутри главное веселье

- Замените существующий код на

для (я в 0..5) {

}

```

Обратите внимание, как вы можете создать цикл for с таким синтаксисом в Kotlin. Далее в цикле for давайте будем генерировать случайное число на каждой итерации.

_Демо — main.kt_

```

- Внутри главное веселье

- Замените существующий код на

для (я в 0..5) {

val randomNumber = Random.nextInt()

}

```

Далее, давайте определим переменную с именем staff:

_Демо — main.kt_

```

Вал персонала: IStaff

```

Теперь вы можете понять, что будет делать эта переменная.

Итак, давайте сделаем забавную вещь внутри цикла for. Давайте назначим переменной staff либо объект класса менеджера, либо класса администратора на основе значения случайного числа, сгенерированного на каждой итерации цикла.

_Демо — main.kt_

```

персонал = если (randomNumber › 10) Менеджер () иначе Администратор()

```

_Обсудить_

```

- если условие возвращает значение

```

Опять же, переменная staff может фактически содержать ссылки на любой объект, класс которого реализует интерфейс Staff.

Итак, внутри цикла for давайте создадим экземпляр ведущего класса на каждой итерации цикла и вызовем его метод приветствия.

_Демо — main.kt_

```

val встреча = Встреча(персонал, «Дэйв»)

println(встреча.приветствовать())

```

Итак, теперь на каждой итерации у нас будет другой объект встречи, и, надеюсь, у каждого объекта будет свой сотрудник, который будет администратором или менеджером.

Это означает, что класс собраний не должен беспокоиться о том, является ли сотрудник на собрании администратором или менеджером. Класс заботится только о том, чтобы поприветствовать человека по имени Дэйв.

Давайте посмотрим на это в действии, запустив функцию main.

_Демо — main.kt_

```

- Запустите главное веселье

```

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

Но у вас все еще может возникнуть вопрос: как это на самом деле делает интерфейсы такими полезными? Мы будем думать об этом так: если бы у нас не было этого интерфейса персонала, нам пришлось бы явно указать переменную персонала, чтобы она была либо менеджером, либо администратором.

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

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

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

Но пока я думаю, что этот пример действительно служит основной цели убедить вас в силе интерфейсов.

```

- Один и тот же персонал на собрании вызывает разные реализации

- Абстракция, достигаемая с развязкой

```