Если вы уже ранее занимались программированием, то наверняка уже в курсе, что в ООП, вместо того чтобы разрабатывать программы как последовательности действий, программисты описывают системы через взаимодействие объектов.
Объект — это сущность, которая объединяет в себе данные и методы работы с этими данными. Это позволяет более эффективно решать сложные задачи, структурируя код таким образом, чтобы он был легче читаем, поддерживаем и расширяем.
Собственной персоной
Сами истоки ООП берут начало с 1960-х годов прошлого века. Однако основные принципы сформировались в 1970-1980х годах. Первым языком с классами и объектами стала Simula (1967), а термин и целостную идею объектного взаимодействия сформулировал Алан Кей, создатель Smalltalk.
Занятный факт состоит в том, что сам Алан Кей за плечами имел опыт и в биологии, и в математике, поэтому основные идеи он вынашивал именно из биологии. Так, различные термины были взяты именно из биологии:
так, каждый объект в ООП ассоциировался с живой клеткой
принцип инкапсуляции служил аналогией с мембраной, что защищает клетку от внешней среды
Ну а взаимодействие через химические сигналы легли в основу того, как именно объекты общаются между собой.
Более того, сам термин Объектно-ориентированный, по мнению Алана Кея, был неудачным, ведь он как бы “зациклил” идею на объектах, хотя цель была именно в том, как именно сущности общаются между собой.
При этом, несмотря на всю популярность и распространенность подхода, не все языки поддерживают ООП в принципе:
Как вы можете увидеть, Python является мультипарадигменным языком и это играет ключевую роль не только в подходе к программированию, но и к тому, как вообще python устроен: в python буквально всё является объектом (числа, функции, классы, модули, etc.).
Главная причина – это то, что классическое программирование зациклено на структурах данных.
Для тех, кто начал изучать программирование в последние десятилетие, возможно, это будет не очень очевидным, но я попытаюсь объяснить 🙂
Если вы изучали основы программирования, то помните, что исходно языки были очень сильно завязаны именно на железе. По сути своей, всё программирование было зациклено на том, как байтики упакованы в памяти, а функции и алгоритмы должны были эти байтики двигать так, чтобы это было наиболее эффективно.
Например, у нас есть цепочка байтов в памяти. Структура этой памяти жестко диктует программисту, какие алгоритмы можно применить к этой структуре, какая у нее будет скорость.
В этом подходе данные и поведение – раздельны. Считалось, что если вы правильно организовали структуру, то и алгоритмы будут короткими и элегантными. Если сделали плохо – то и код будет хаотичным.
Сама логика, зачем мы все это делаем и для каких целей, скорее существовала непривязанной к тому, что лежит в памяти. Отсюда и слабая связность с тем, что именно мы делаем с кодом.
Здесь включается логика ООП. Объекты позволяют связать функции и структуру вместе. К структурам мы фактически “приклеиваем” функции (которые называют методами) для работы именно с этой структурой.
Так, в ООП программировании вопрос “Что программа должна сделать?” заменяется на “Какие объекты здесь есть и как они связаны?”.
Другими словами, Объекты в парадигме ООП – это некие сущности, которые могут объединяться в целые системы, воздействуя друг на друга и меняя свойства друг друга. Сами же задачи в этой парадигме решаются путем создания подходящих объектов и организации их взаимодействия.
Мозг лопнул? Давайте на другом примере.
Если мы вернемся в реальный мир, то обнаружим, что всё, что есть вокруг нас – это некие объекты.
Каждый объект вокруг нас мы можем описать, путём ответов на некоторые вопросы:
Какие свойства у этого объекта?
Что этот объект делает?
Как мы можем взаимодействовать с объектом?
Какие свойства и действия объединяют этот объект с другими?
Вот, например, апельсин:
Свойства: круглый, N-диаметра, состоит из кисло-сладких долек с косточками и оранжевой кожуры
Что может сам делать: растет на дереве, спеет
Взаимодействие с ним: очистить, разделить дольки
Объединение с другими объектами: свойства глобально объединяют в класс Цитрусовые. Такую группу объектов – с общими свойствами и поведением – и называют классом.
Мы можем описать объект, и нам досконально, в целом, не нужно знать каким образом он спеет, сколько косточек внутри (хотя, кому как, конечно), не нужно знать, какие еще цитрусовые с ним в подвиде…
Глобально нас волнует, как мы можем его съесть и как его определить по свойствам. А то, что каждая долька состоит из ещё оболочки и внутри нее куча огромных клеток, а еще там семечка генетический материал несет.. это всё лирика.
Возьмите любой предмет из вашего окружения и попробуйте описать его также, как выше я описала для вас апельсин.
Опишите два разных объекта, которые хочется объединить в одну группу-класс (например, легковая машина и грузовик -> класс Автомобиль). Ответьте на вопросы:
Что у этих объектов общего, а чем они различаются?
Какие у них общие действия, а какие – принадлежат только конкретному объекту?
В этом задании поработайт ене с физическим объектом, а с виртуальным. Возьмите, например, элемент любого приложения – кнопку, плейлист, уведомление, поиск. Опишите его тем же четырьмя вопросами: его свойства, что делает сам, как с ним взаимодействовать, во что объединяется с другими.
Так и у разработчиков, но с одним глобальным отличием: разработчики имеют дело с абстрактными объектами, которые, тем не менее, можно видеть.
Программисты могут разрабатывать собственные группы объектов, у которых будет всё, что есть у нашего апельсина в примере: какие-то свойства, что можно с ними делать, что они сами могут делать и по каким признакам группа объединяется. Глобально это называют интерфейсом (не путать с визуальным интерфейсом).
Например, вы решили сделать своё приложение для компьютера. Такое приложение можно представить как систему, состоящую из различных элементов: кнопок, баров, полей ввода, объектов меню и т.д. Каждый из этих элементов – это цифровой объект, в который “вшит” его интерфейс. С помощью этих интерфейсов мы можем менять интерфейсы других объектов.
Главное, что надо знать, что в ООП парадигме каждый программист может разрабатывать что-то своё. Важно лишь заранее договориться, как именно объекты будут взаимодействовать между собой, — этот договор и называют интерфейсом.
Условному Диме (который разрабатывает клавиатуры для смартфонов) нужно лишь знать, как достать код из буфера обмена. То, что реализация Наташи спрятана от Димы, и называют сокрытием (инкапсуляцией).
Буфер обмена здесь — и есть тот самый интерфейс: общий договор, через который два объекта обмениваются данными, не заглядывая друг другу внутрь.
Ключевая разница, которая нас должна волновать – это то, как именно пишутся программы в структурном и объектно-ориентированном стиле.
В первом случае, на первый план выходит логика, понимание последовательности выполнения команд для достижения нужной нам цели.
Во втором – сначала представляем систему как набор объектов с их интерфейсами, а уже потом реализуем взаимодействие между ними.
Возьмем телевизор (или приставку, как вам нравится). Пульт не знает, как именно телевизор меняет картинку. Опишите "договор" между ними: какой набор команд-сообщений телевизор обязан понимать. Что пульту знать не нужно?
Почему любой прибор работает от любой розетки в стране? Что здесь играет роль "общего договора"? А что сломается. если производитель придумает свою форму вилки?
Кнопка «Играть» в плеере запускает и радио, и загруженный файл, и стриминг. Опишите, что у них общий интерфейс («играть / пауза / следующий»), а реализация у каждого своя. Как добавить четвёртый источник, не трогая сами кнопки?
Так мы подошли к основным понятиям, которые используются в ООП: Класс, объект, наследование, инкапсуляция и полиморфизм.
Однако должна вас предупредить. В некоторых языках те или иные понятия реализуются куда более строго, чем в Python или даже в JS (строго говоря, в JS даже нет ООП как такового, он реализован через прототипы, а не классы, но мы не об этом сегодня).
Так или иначе, все "столпы" будут рассмотрены в полной мере и, надеюсь, тема ООП вас не будет после этого пугать примерно никогда 😄