Найти в Дзене
"Мы"-Прогер

Изучаем C# - Абстракции в ООП. Интерфейсы

В бытовом смысле, например, автомобильный интерфейс означает руль, педали, спидометр и тахометр, кнопки, то есть, приборы, через которые водитель взаимодействует с автомобилем. Слово "Интерфейс" и переводится как внешний вид для взаимодействия. Благодаря тому, что руль и педали на всех автомобилях работают одинаково, то есть, разные автомобили имеют одинаковый интерфейс, водителю не нужно переучиваться, чтобы взаимодействовать с другим автомобилем. Также и в программировании: интерфейс - набор публичных методов, которые видны тем, кто взаимодействует с классом. Например, для класса интерфейс будет Потому что там 3 публичных метода с вот таким описанием. Для чего это нужно? Мы можем заменить один класс на другой и тот код, который с ним работает, не придётся переписывать, если интерфейс останется тем же самым. Например, мы пишем большую программу, которая работает с базой данных. Если всю работу с базой данных мы вынесем в отдельный класс, то мы сможем сменить одну базу данных на другую
Оглавление

Что такое интерфейс

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

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

Например, для класса

интерфейс будет

-2

Потому что там 3 публичных метода с вот таким описанием.

Зачем нужны интерфейсы

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

Интерфейс
Интерфейс
Класс должен реализовывать интерфейс
Класс должен реализовывать интерфейс
Переменная объявляется с типом интерфейса
Переменная объявляется с типом интерфейса

Переменная databaseHelper имеет тип IDatabaseHelper, то есть, мы имеем доступ только к тем методам, которые есть в интерфейсе. Если какой-то метод класса PostgresHelper отсутствует в интерфейсе IDatabaseHelper, то мы не сможем его использовать, потому что по синтаксису переменная имеет тип IDatabaseHelper, а не PostgresHelper. Таким образом, мы будем работать только с теми методами, которые есть в интерфейсе. А если нам понадобится поменять PostgresHelper на какой-нибудь MsSqlHelper, то мы просто унаследуем его от этого же интерфейса и автоматически будем обязаны реализовать все методы, которые там есть:

-6

Если мы забудем хотя бы один метод, будет такая ошибка компиляции.

Более того, все использования переменной databaseHelper останутся как были, потому что она как была типа IDatabaseHelper, так и останется. Не нужно будет менять типы таких переменных или вызовы методов. Надо будет поменять только место её создания:

-7

Принцип абстракции в ООП

Как мы только что увидели, чтобы использовать функционал "подключения" к базе данных PostgresHelper или MsSqlHelper, мы не должны знать, какой код написан внутри них. Нам достаточно знать только публичные методы: например, что у них есть метод ExecuteNonQuery(), что он получает на вход строку и что ничего не возвращает в ответ. Таким образом, мы приходим к четвёртому принципу объектно-ориентированного программирования - принципу абстракции: используя интерфейсы, мы абстрагируемся от реализации методов. Нам достаточно знать только как вызывать публичные методы. То есть, нам достаточно знать только интерфейс. Это также подобно принципу "чёрного ящика": мы знаем, какие у него есть рычажки снаружи, а что внутри - нам неважно. У того же автомобиля, чтобы его водить, достаточно уметь использовать руль и педали и совсем не нужно знать детали его устройства. Точно так же и в программировании.

Ещё про интерфейсы

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

Классы могут наследоваться от интерфейсов (говорят - "реализовывать интерфейсы") точно так же, как от обычных классов. При этом класс должен либо реализовать все публичные методы интерфейса, либо оставить какие-то методы нереализованными (то есть, с ключевым словом abstract) и сам стать абстрактным.

Поскольку свойства в C# - это, по сути, два метода (геттер и сеттер), то свойства применительно к интерфейсам рассматриваются как методы.

Для примера выделим из класса BaseAnimal ("базовое животное") два интерфейса: INamedObject ("объект, имеющий имя") и IMovableObject ("объект, который можно двигать"):

Класс "Животное"
Класс "Животное"
Интерфейс "Объект, имеющий имя"
Интерфейс "Объект, имеющий имя"
Интерфейс "Объект, который можно двигать"
Интерфейс "Объект, который можно двигать"

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

-11

Проблема множественного наследования

А вот наследоваться можно только от одного класса. Это вызвано тем, что в разных классах могут быть свои реализации метода. Например, в Class1 метод Method1() печатает "Class1", а в Class2 тот же самый метод печатает "Class2":

-12

Тогда было бы непонятно, какую именно реализацию метода должен использовать класс-наследник ChildClass, который наследуется и от Class1, и от Class2 одновременно:

-13

В C++ было, что выбирается метод родителя, стоящего ближе к началу, но это очень криво и неочевидно. Поэтому в C#, Java и многих других си-подобных языках множественное наследование запрещено.

Но если наследоваться от интерфейсов (точнее, реализовывать интерфейсы), проблемы не возникнет, ведь интерфейсы не содержат никакой логики. Соответственно, если ChildClass реализует и Interface1, и Interface2, то оба интерфейса всего лишь говорят ему: у тебя должен быть метод Method1(), но не дают его реализаций, которые могли бы конфликтовать между собой. Метод остаётся нереализованным, так что реализовывать его обязан сам ChildClass или его наследник:

-14

Далее

Пишем статические поля и методы. Паттерн Singleton

Оглавление

Изучаем C# с нуля - Очень краткий курс - Оглавление
"Мы"-Прогер27 января