Концепции ООП

Концепции ООП

На прошлом уроке я подвёл вас к основной идее ООП: повышение уровня абстракции за счёт объединения процедур и данных в "объект". Эта идея остаётся неизменной, какой бы конкретный язык, реализующий объектный подход, мы бы ни выбрали. Однако способы достичь объектности у разных языков разные. Мы будем рассматривать ООП применительно к Python, но имейте в виду, что в других языках отдельные моменты программирования в объектном стиле будут отличаться, порой — сильно!

Объекты и классы

Итак, в Python объекты — это значения, создаваемые на основе шаблона — класса. Программист описывает с помощью специального синтаксиса содержимое класса и потом во время исполнения создаёт объекты — экземпляры (instances) этого класса. У класса есть свои данные — атрибуты класса. К ним имеют доступ все экземпляры класса. При этом экземпляры имеют свои атрибуты — атрибуты экземпляра. Эти данные доступны только объекту владельцу.

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

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

Инкапсуляция

Инкапсуляция — это упаковывание данных и поведения (процедур, работающих с данными) в один объект. Инкапсуляция преследует всё ту же цель — сокрытие сложности за абстракцией. Но просто так складывать всё подряд в какой-то объект не следует. Данных и поведения должно быть столько, сколько необходимо и достаточно: объект должен хранить все свои и только свои данные самостоятельно и предоставлять все необходимые средства для манипуляции этими данными.

Представим для примера, что у нас смоделирован объект "человек". Человек может иметь домашних питомцев. Так вот с точки зрения инкапсуляции неверно будет хранить питомцев где-то в отдельном списке: питомцы принадлежат человеку, это часть данных модели человека в нашей системе. Делаем вывод: список питомцев должен быть инкапсулирован в объект "человек".

Теперь представим, что нам нужно прикреплять питомцев к уже существующему человеку. Если мы дадим прямой доступ к списку питомцев и разрешим делать с этим списком любые преобразования, возможные для обычных списков, то мы можем получить человека, питомцами которого являются два десятка чисел и строк, а также пароход, файл и None! По-хорошему, программист, работающий с нашей моделью человека, вообще не должен знать, что питомцы хранятся в списке, ему достаточно (и необходимо) метода "добавить питомца" — вот это и есть абстракция!

Полиморфизм

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

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

Так вот, код, который работает с разными объектами без точного знания того, с чем он работает в данный момент, и использующий только лишь их (объектов) общие свойства, называется полиморфным. А возможность писать такой код — и есть полиморфизм.

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

В приведённом выше примере про человека и питомцев мы можем ввести такую абстракцию: питомцем может считаться что угодно, чем человек может владеть и о чём может заботиться, получая от заботы удовольствие (очень абстрактное описание понятия "питомец", не правда ли?). Под эту абстракцию подойдёт, например, камень, или игрушечный робот — его можно любить, о нём можно заботиться (мыть камень, менять батарейки у робота). Вот такая вот забавная абстрактная модель взаимоотношений человека с питомцем :)

Наследование

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

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

Всё в том же примере системы с людьми и питомцами все питомцы (соответствующие классы) семейства кошачьих могут иметь общего предка (тоже класса) "Абстрактная Кошка". Про которую известно, что она умеет прыгать и пить молоко. Это знание позволит нам, всего лишь проверив принадлежность конкретного питомца к Абстрактным Кошкам, понять, чем мы можем питомца кормить и хватит ли невысокого забора вокруг жилища, чтобы питомец не убежал.

Тут вы можете даже увидеть связь наследования с полиморфизмом: если мы знаем, что питомец — кошка, то может статься, что большего нам знать и не нужно. Получается полиморфный код, работающий только с кошками, но зато с любыми!

ООП и реальный мир

Во многих источниках информации об ООП говорят о том, что объектный подход интуитивен, ведь он позволяет описывать реальный мир. После знакомства с подходом при подобном его позиционировании разработчик часто начинает строить иерархии классов, подобные существующим в реальности: "млекопитающие — кошачьи — тигры". Вот только у ООП нет такой цели — моделировать жизнь!

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

ООП — это всего лишь развитие существовавших и до появления самого термина "Объектно Ориентированное Программирование" инструментов. Объекты в голове программиста существовали уже тогда, когда он использовал только структуры данных и процедуры для работы с оными. Выделение подхода ООП всего лишь систематизировало уже привычные техники, внесло общую терминологию и общие техники для решения типичных задач (те самые "паттерны проектирования").

Предметная область — те самые игра, игроки, персонажи, битвы — тоже поддаётся моделированию с помощью объектов. Но моделирование это должно делаться не для красоты самой модели, не для составления каталога игровых сущностей, а для упрощения написания кода, решающего конкретную задачу (написания игры)!

Мы учим программированию с нуля до стажировки и работы. Попробуйте наш бесплатный курс «Введение в программирование» или полные программы обучения по Javascript, PHP, Python и Java.

Хекслет

Подробнее о том, почему наше обучение работает →