Зачем нужны абстракции и интерфейсы
Как в старом анекдоте: про объектно-ориентированное программирование можно рассказать просто и неправильно либо сложно и неправильно. Мы попробуем рассказать про очередной аспект ООП просто.
Зачем это: ООП — одна из главных концепций современной разработки. Она применима не к каким-то конкретным языкам, это скорее способ мышления в программировании. Если вы понимаете ООП, ваш код на любом языке будет чище, читаемее и эффективнее.
В этой статье разберём два сложных понятия из объектно-ориентированного программирования: абстракции и интерфейсы. Это ещё одна ступень в понимании непостижимого.
Основные идеи из ООП
- Объектно-ориентированное программирование построено вокруг объектов. Можно представить, что объект — это коробка, в которой лежат данные и функции.
- Деление на объекты нужно для того, чтобы можно было создавать, обслуживать и переделывать части программы, не влияя на другие части и программу в целом. По-умному это называется «для повышения уровня абстракции».
- Смысл объекта в том, что он умеет делать какие-то свои дела, и остальные объекты не должны знать, как он это делает.
- У объекта есть понятие атрибута и метода. Атрибут — это любые данные, которые хранятся в «коробке» объекта. Методы — это любые действия, которые можно совершать над объектом или внутри его. Атрибуты обычно выражаются переменными, а методы — функциями.
- Объекты необходимы, например, в компьютерных играх, где каждая штучка на игровом поле — это объект с какими-то свойствами. Или в интернет-магазине, где один объект отвечает за корзину, другой — за выкладку товара.
- Объекты можно создавать по шаблону — такие шаблоны называются классами.
Абстракция
Представьте, что вы попросили нескольких человек описать в общих чертах, что такое телефон и как им пользоваться: пусть это будут бабушка, мама и подруга. Бабушка вспомнит про дисковые телефоны и трубки с витым проводом. Мама расскажет про радиотелефоны, у которых есть база и есть трубка, с которой можно ходить по всей квартире, а подруга начнёт описывать мобильник.
Несмотря на то что рассказы будут сильно отличаться между собой, у них будет несколько общих моментов про телефон:
- у телефона есть трубка;
- в трубку мы говорим, из трубки — слушаем;
- можно набрать номер нужного человека и позвонить ему;
- если вам позвонят по телефону, вы это услышите и примете звонок.
Получается, что если представить абстрактный телефон, то получится такое устройство с динамиком, микрофоном и средством набора номера.
Это и есть абстракция: когда мы описываем только самые существенные детали, которые важны для задачи. В нашем случае задача такая — понять, что такое телефон и как им пользоваться. Поэтому микрофон и динамик для этой задачи важен, а способ связи телефона с сетью — нет. Устройство набора номера важно, а то, какая мелодия играет при вызове — нет.
🔥 Абстракция — это когда мы сосредотачиваемся только на существенных для задачи деталях и игнорируем всё остальное. В ООП абстракция означает, что для каждого объекта мы задаём минимальное количество методов, полей и описаний, которые позволят нам решить задачу. Чем меньше характеристик, тем лучше абстракция, но ключевые характеристики убирать нельзя.
Чтобы работать с абстракциями, используют интерфейсы.
Интерфейс
Итак, у нас есть некое устройство с трубкой, микрофоном, динамиком и средством набора номера. Но если вы вспомните рассказы мамы, бабушки и подруги, то обнаружите вот что:
- в микрофон говорят, чтобы собеседник мог вас услышать;
- чтобы слышать самому, ухо прикладывают к динамику;
- чтобы набрать номер, нужно с помощью номеронабирателя вызвать нужную последовательность цифр;
- когда идёт вызов, слышны гудки в динамике.
Всё это — интерфейсы. Они позволяют работать с объектом, не вникая в то, как он устроен внутри. Если вы умеете работать с интерфейсом номеронабирателя, то вам всё равно, нужно ли крутить диск, нажимать физические кнопки на радиотрубке или давить пальцем на сенсорный экран.
Такой интерфейс как бы говорит нам — я передам в телефон любые цифры, какие захочешь. Как я это сделаю внутри и как они будут обработаны — неважно, просто набери номер, а дальше телефон сам разберётся.
Интерфейсы — это действия над объектом, доступные другим объектам (поэтому они называются публичными).
Есть ещё инкапсулированные, то есть внутренние методы. Например, у микрофона есть публичный метод «Слушать голос», и есть внутренний метод «Преобразовать голос в электрические сигналы». С его помощью он взаимодействует с другими частями нашего абстрактного телефона. Про инкапсуляцию будет отдельный материал, потому что тема большая.
Сложная терминология
Строго говоря, интерфейсы — это не действия, а методы. Сейчас объясним.
В программировании есть операции — это простейшие действия, например, скопировать значение из одной переменной в другую.
Из простых действий составляются функции — это когда несколько операций «склеиваются» в нечто единое. Мы даём этой склейке название и получаем функцию. Например, может быть функция «проверить правильность электронного адреса», которая состоит из нескольких десятков простых операций.
На языке ООП функции, привязанные к объектам, называются методами. Просто такой термин. По сути это функции, то есть склеенные вместе операции.
Итого: метод — это набор простых действий, которые склеили в единое целое и засунули в объект.
Для чего это всё
Допустим, вы работаете в команде над большим продуктом. В таких случаях удобно разделить одну большую программу на множество мелких подпрограмм и сервисов, каждый из которых решает свою узкую задачу.
Если заранее не договориться о том, как эти компоненты обмениваются данными между собой, то может случиться то, о чём мы уже предупреждали:
- один программист делает функцию, которая отвечает за регистрацию новых пользователей;
- все остальные используют эту функцию, привыкли к её параметрам и знают, что туда нужно передавать;
- внезапно этот программист понимает, что можно запрограммировать более эффективный вариант регистрации, который будет работать гораздо быстрее;
- он полностью переписывает функцию, и в этот момент у всей команды ломается логика программы: старые вызовы не работают, потому что функция теперь принимает другие данные (или в другой последовательности).
Чтобы такого не было, поступают так:
- Один программист отвечает за регистрацию новых пользователей.
- Он делает объект «Пользователь» и прописывает ему интерфейс «Зарегистрировать».
- Также он говорит, что интерфейс «Зарегистрировать» будет принимать на вход три переменные: имя, почту и пароль.
- Теперь программист говорит остальным: «Ребята, если нужно зарегистрировать нового пользователя — используйте интерфейс Пользователь.Зарегистрировать(имя,почта,пароль)».
- Даже если внутри объекта поменяется вся логика работы, то это никак не повлияет на интерфейс — все так же смогут им пользоваться.
- А всё потому, что никому нет дела, как тот программист реализовал свою часть, если через интерфейс всё работает нормально. Неважно, как он шифрует пароль, где хранит почту, как обрабатывает имя и в какую базу данных всё это складывает. Если интерфейс работает, все остальные могут продолжать разработку.
Основные принципы ООП: абстракция в программировании
Абстракция — один из принципов ООП в программировании. По своей сути это процесс выделения общих характеристик и функциональности объектов или системы, игнорируя детали реализации.
Для чего нужна абстракция в программировании?
Абстракция позволяет разрабатывать программы на различных языках программирования, скрывая сложность и детали нижележащего кода. Это делается для упрощения сложных систем и концепций, чтобы разработчики могли фокусироваться на основных аспектах проблемы и легче понимали код.
Преимущества абстракции в ООП
В объектно-ориентированном программировании абстракция играет важную роль. Она позволяет создавать абстрактные классы и интерфейсы, которые определяют общие свойства и методы, не зависящие от конкретной реализации. Преимущества абстракции ООП включают:
- Упрощение сложности: абстракция в программировании позволяет скрыть детали реализации и сосредоточиться на ключевых аспектах системы. Это помогает упростить понимание и поддержку кода.
- Модульность: возможность разбить систему на модули или классы, которые могут работать независимо друг от друга. Это способствует повторному использованию кода и улучшает масштабируемость проекта.
- Повышение безопасности: абстракция позволяет скрыть некоторые детали реализации, что делает код более безопасным и защищенным. Внешние компоненты не имеют прямого доступа к внутренним деталям объекта или системы.
Пример абстракции в ООП
В качестве примера реализуем абстрактный класс «Фигура» и его наследников на языке Java:
abstract class Shape < protected String color; public Shape(String color) < this.color = color; >// абстрактный метод для получения площади public abstract double getArea(); // абстрактный метод для получения периметра public abstract double getPerimeter(); // общий метод для вывода информации о фигуре public void printInfo() < System.out.println("Цвет: " + color); System.out.println("Площадь: " + getArea()); System.out.println("Периметр: " + getPerimeter()); >> class Circle extends Shape < private double radius; public Circle(String color, double radius) < super(color); this.radius = radius; >@Override public double getArea() < return Math.PI * radius * radius; >@Override public double getPerimeter() < return 2 * Math.PI * radius; >> class Rectangle extends Shape < private double length; private double width; public Rectangle(String color, double length, double width) < super(color); this.length = length; this.width = width; >@Override public double getArea() < return length * width; >@Override public double getPerimeter() < return 2 * (length + width); >> public class Main < public static void main(String[] args) < Circle circle = new Circle("Красный", 5.0); circle.printInfo(); System.out.println(); Rectangle rectangle = new Rectangle("Синий", 4.0, 6.0); rectangle.printInfo(); >>
В этом примере абстрактный класс Shape содержит общие свойства и методы для всех фигур. У него есть абстрактные методы getArea() и getPerimeter() , которые должны быть реализованы в наследниках. Классы Circle и Rectangle наследуют абстрактный класс Shape и реализуют абстрактные методы в соответствии с логикой для каждой фигуры.
В методе main() создаются объекты Circle и Rectangle , которые вызывают метод printInfo() , чтобы вывести информацию о каждой фигуре, включая цвет, площадь и периметр.
Пример показывает, как абстракция в ООП позволяет определить общий интерфейс (абстрактный класс) и реализовать его в конкретных классах, обеспечивая гибкость и повторное использование кода.