На прошлом уроке мы подошли к основной идее ООП: повышение уровня абстракции за счет объединения процедур и данных в "объект". Эта идея остается неизменной, какой бы конкретный язык, реализующий объектный подход, мы бы ни выбрали. Однако, способы достичь объектности у разных языков разные. Мы будем рассматривать ООП применительно к Python, но имейте в виду, что в других языках отдельные моменты программирования в объектном стиле будут отличаться, порой — сильно!
Объекты и классы
В Python объекты — это значения, создаваемые на основе шаблона — класса. Программист описывает с помощью специального синтаксиса содержимое класса и потом во время исполнения создает объекты — экземпляры (instances) этого класса. У класса есть свои данные — атрибуты класса. К ним имеют доступ все экземпляры класса. При этом экземпляры имеют свои атрибуты — атрибуты экземпляра. Эти данные доступны только объекту.
Технически в Python любой объект может получить доступ к содержимому любого другого объекта, если имеет ссылку на него. Но на уровне добровольных соглашений такой доступ можно ограничивать.
Некоторые атрибуты могут быть функциями. В этом случае такие атрибуты называют методами. Вы уже пользовались методами списков и словарей, так что некоторое представление о методах у вас имеется!
Инкапсуляция
Инкапсуляция — это упаковывание данных и поведения (процедур, работающих с данными) в один объект. Инкапсуляция преследует все ту же цель — сокрытие сложности за абстракцией. Но просто так складывать все подряд в какой-то объект не следует. Данных и поведения должно быть столько, сколько необходимо и достаточно: объект должен хранить все свои и только свои данные самостоятельно и предоставлять все необходимые средства для манипуляции этими данными.
Представим для примера, что у нас смоделирован объект "человек". Человек может иметь домашних питомцев. Так вот с точки зрения инкапсуляции неверно будет хранить питомцев где-то в отдельном списке: питомцы принадлежат человеку, это часть данных модели человека в нашей системе. Делаем вывод: список питомцев должен быть инкапсулирован в объект "человек".
Теперь представим, что нам нужно прикреплять питомцев к уже существующему человеку. Если мы дадим прямой доступ к списку питомцев и разрешим делать с этим списком любые преобразования, возможные для обычных списков, то мы можем получить человека, питомцами которого являются два десятка чисел и строк, а также пароход, файл и None! По-хорошему, программист, работающий с нашей моделью человека, вообще не должен знать, что питомцы хранятся в списке, ему достаточно (и необходимо) метода "добавить питомца" — вот это и есть абстракция!
Полиморфизм
Полиморфизм ("многообразие форм" по-гречески) позволяет смотреть на разные объекты так, чтобы с определенной точки зрения они были похожи. Под похожестью здесь мы подразумеваем одинаковое поведение, то есть возможность выполнить одни и те же действия.
Например, для того, чтобы произвести перекличку, мне достаточно знать, что все опрашиваемые субъекты могут назвать себя. И в данном случае не важно, у кого мы спрашиваем имя — у человека, робота или говорящего динозавра.
Так вот, код, который работает с разными объектами без точного знания того, с чем он работает в данный момент, и использующий только лишь их (объектов) общие свойства, называется полиморфным. А возможность писать такой код — и есть полиморфизм.
Как вы можете уже догадаться, полиморфизм тоже связан с абстракцией: полиморфному коду достаточно знать об объектах только важные ему сведения, от остального знания код абстрагируется!
В приведенном выше примере про человека и питомцев мы можем ввести такую абстракцию: питомцем может считаться что угодно, чем человек может владеть и о чем может заботиться, получая от заботы удовольствие (очень абстрактное описание понятия "питомец", не правда ли?). Под эту абстракцию подойдет, например, камень, или игрушечный робот — его можно любить, о нем можно заботиться (мыть камень, менять батарейки у робота). Вот такая вот забавная абстрактная модель взаимоотношений человека с питомцем :)
Наследование
Наследование — свойство объектной модели устанавливать связь между классами так, что классы-потомки получают (наследуют) те же свойства и поведение, которыми обладают классы-предки. Одни и те же классы могут быть потомками одних классов и при этом являться предками для других — так получаются "иерархии классов".
Иногда такие иерархии повторяют иерархии объектов реального мира, в других ситуациях сущности, описываемые классами могут описывать что-то, не имеющее аналогов за пределами модели. Но во всех случаях мы опять же получаем инструмент для абстрагирования: если мы знаем, что некий класс реализует нужное нам поведение, то мы можем предполагать, что и все его потомки, в том числе и непрямые, будут этим поведением обладать!
Все в том же примере системы с людьми и питомцами все питомцы (соответствующие классы) семейства кошачьих могут иметь общего предка (тоже класса) "Абстрактная Кошка". Про которую известно, что она умеет прыгать и пить молоко. Это знание позволит нам, всего лишь проверив принадлежность конкретного питомца к Абстрактным Кошкам, понять, чем мы можем питомца кормить и хватит ли невысокого забора вокруг жилища, чтобы питомец не убежал.
Тут вы можете даже увидеть связь наследования с полиморфизмом: если мы знаем, что питомец — кошка, то большего нам знать и не нужно. Получается полиморфный код, работающий только с кошками, но зато с любыми!
ООП и реальный мир
Во многих источниках информации об ООП говорят о том, что объектный подход интуитивен, ведь он позволяет описывать реальный мир. После знакомства с подходом при подобном его позиционировании разработчик часто начинает строить иерархии классов, подобные существующим в реальности: "млекопитающие — кошачьи — тигры". Вот только у ООП нет такой цели — моделировать жизнь!
Программы пишутся для компьютеров. И пишутся в основном не биологами или астрономами, а "компьютерщиками". Поэтому гораздо больше шансов встретить объект-дерево, моделирующий не "березу", а "красно-черное" (и это не слегка подгоревший осенью клен!). Программисту нужно управлять сложностью кода, а не каталогизировать флору и фауну, вот он и абстрагирует сущности, выделяя их из кода, из алгоритмов!
ООП — это всего лишь развитие существовавших и до появления самого термина "Объектно Ориентированное Программирование" инструментов. Объекты в голове программиста существовали уже тогда, когда он использовал только структуры данных и процедуры для работы с ними. Выделение подхода ООП всего лишь систематизировало уже привычные техники, внесло общую терминологию и общие техники для решения типичных задач (те самые "паттерны проектирования").
Предметная область — игра, игроки, персонажи, битвы — тоже поддается моделированию с помощью объектов. Но моделирование это должно делаться не для красоты самой модели, не для составления каталога игровых сущностей, а для упрощения написания кода, решающего конкретную задачу (написания игры)!
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Вебинар «Как самостоятельно учиться»
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.