Объектно-ориентированное программирование (ООП) – парадигма разработки приложений, предусматривающей моделирование различных компонентов компьютерного приложения, основываясь на реальных объектах.
В свою очередь, под объектом подразумевается что-то, что имеет определенные свойства и что способен осуществлять определенные действия.
Предположим, необходимо создать болид Формулы-1 с помощью инструментов ООП. В первую очередь, необходимо определить реальные объекты в гонке. Какие аспекты этого мероприятия имеют определенные характеристики и способны выполнять определенную задачу?
Первый ответ, который придет в голову, – это гоночный болид. Он может иметь следующие свойства:
- Мощность двигателя.
- Марка.
- Модель.
- Производитель.
Возможны и другие особенности. Здесь важно понять логику. С болидом возможно выполнение разнообразных действий: запуска, остановки, ускорения или наоборот, замедления.
Еще один объект – это гонщик. У него есть такие характеристики, как национальность, возраст, пол и другие. Помимо этого, у него есть определенный набор функций, таких как управление болидом, рулевое управление, переключение передач.
Аналогично этому примеру, в ООП под объектами подразумеваются аспекты программы, которые имеют определенный набор связанных с ними характеристик, а также функционал.
Учтите то, что ООП – это концепция, которая не зависит от конкретного языка. Подавляющее число языков, таких как Java, C++, Python, являются объектно-ориентированными.
Достоинства и недостатки
Давайте проанализируем ряд положительных сторон объектно-ориентированной разработки приложений:
- В объектно-ориентированном программировании один и тот же блок приложения может использоваться многократно. Нет необходимости заново писать код. Достаточно импортировать объект и задать его параметры, после чего можно попросить его выполнить то или иное действие.
- Применение модулярного подхода в ООП дает возможность получить код, который будет максимально гибким и доступным к чтению.
- Каждый класс в ООП решает конкретную задачу. Если в определенной части кода появляется исключение, его можно обработать без надобности изменять другие части приложения.
- Инкапсуляция позволяет сделать программу более безопасной.
Несмотря на то, что ООП имеет ряд очевидных достоинств, минусы у такого подхода также имеются:
- Необходимо иметь полное понимание о той программе, которая разрабатывается.
- Не все аспекты ПО – это оптимальное решение по реализации таким способом. Могут возникнуть некоторые дополнительные сложности для новичков.
- По мере добавления новых классов в код, программа становится все более сложной. Причем рост происходит не линейно, а экспоненциально.
Далее проанализируем наиболее значимые концепции ООП.
Как понятно из названия этой концепции разработки приложений, ООП – это про объекты. Тем не менее для создания объекта сперва необходимо обозначить его класс.
Что такое класс?
Под классом подразумевается что-то типа чертежа, по которому создается объект. Его нередко сравнивают со схемой дома. Достаточно посмотреть на нее и понять, какой внешний вид у дома.
Сам по себе класс не представляет ничего. Так, схема – это не дом. Тем не менее она дает понимание того, как он выглядит в норме.
Приведем еще один пример, который позволяет выразить соотношение между классом и объектом нагляднее. Есть машина, и есть Audi. Конечно, последняя тоже является автомобилем. Тем не менее, машины, по факту, нет. Это абстрактная концепция, которая находит свою реализацию в Honda, Toyota, Mercedes и так далее.
Чтобы создать класс, задействуется ключевое слово class. Имя класса идет непосредственно за этим ключевиком, а потом обязательно нужно поставить знак двоеточия. Тело класса стартует с новой строчки, с отступом на одну вкладку влево.
Рассмотрим, как создается наиболее простой класс в Python. Посмотрите на этот фрагмент кода.
# Создаем класс Car class Car: # создаем атрибуты класса name = "c200" make = "mercedez" model = 2008 # создаем методы класса def start(self): print ("Заводим двигатель") def stop(self): print ("Отключаем двигатель")
В этом примере нами был создан класс под названием Car, у которого есть три атрибута: name, make, model, которые означают имя, марку и модель соответственно.
Также этот класс имеет два метода – start() и stop(), которые выдают сообщения о том, что двигатель заводится или отключается.
Объекты
Прежде мы разобрались в том, что класс напоминает некий чертеж, по которому создается уже объект. Тем не менее для реального использования объектов и методов, надо создать объект на основе этого класса. Есть ряд методов и атрибутов класса, доступных для использования за пределами объекта.
А сейчас нужно просто запомнить, что изначально создается объект класса, и только потом можно использовать его методы и атрибуты.
В качестве синонима объекта нередко используется слово «экземпляр». При этом, процедура создания объекта класса называется инициализацией. В Python, для создания объекта класса, необходимо лишь вписать его имя со скобками, которые открываются и закрываются.
Сгенерируем экземпляр класса Car, созданного ранее.
# Создаем объект класса Car под названием car_a car_a = Car() # Создаем объект класса Car под названием car_b car_b = Car()
Здесь было создано два экземпляра класса Car: car_a и car_b. Чтобы узнать тип объектов, которые нами были созданы, возможно использование метода type с дальнейшей передачей ему названий объектов. Давайте вы попробуете выполнить такой код.
print(type(car_b))
Когда вы это сделаете, в выдаче увидите следующую строку.
<class '__main__.Car'>
Это указывает на то, что тип объекта car_b – класс Car.
На данный момент нами был создан класс и объекты, которые ему соответствуют. Теперь наступило время получить доступ к его атрибутам и вызвать метод с использованием объекта класса. Чтобы сделать это, необходимо только вписать название объекта, за которым идет оператор . (точка), а также название атрибута либо метода, к какому вы желаете получить доступ либо вызов.
Давайте рассмотрим такой пример.
car_b.start()
В данном скрипте нами был вызван метод start() через объект car_b. Выдача будет следующей.
Заводим двигатель
По аналогии, вы можете получить доступ к атрибуту с помощью такого синтаксиса.
print(car_b.model)
В выдаче отобразится модель.
2008
Атрибуты класса
Ранее мы поняли, как генерировать объекты класса и как они могут использоваться для получения доступа к определенным атрибутам класса.
В Python, каждый из объектов включает определенные атрибуты по умолчанию и методы в дополнение к конкретным атрибутам, созданным разработчиком. Чтобы получить перечень всех атрибутов и методов объекта, используется специальная функция dir().
Попробуем посмотреть на все атрибуты объекта car_b, созданногоранее. Выполните такой скрипт.
print(dir(car_b))
В выдаче вы увидите такие атрибуты.
[‘__class__’,
‘__delattr__’,
‘__dict__’,
‘__dir__’,
‘__doc__’,
‘__eq__’,
‘__format__’,
‘__ge__’,
‘__getattribute__’,
‘__gt__’,
‘__hash__’,
‘__init__’,
‘__init_subclass__’,
‘__le__’,
‘__lt__’,
‘__module__’,
‘__ne__’,
‘__new__’,
‘__reduce__’,
‘__reduce_ex__’,
‘__repr__’,
‘__setattr__’,
‘__sizeof__’,
‘__str__’,
‘__subclasshook__’,
‘__weakref__’,
‘make’,
‘model’,
‘name’,
‘start’,
‘stop’]
Данная встроенная функция будет очень полезной для изучения атрибутов и функций того или иного экземпляра. Особенно если используется REPL.
Атрибуты класса против атрибутов объектов
В целом, выделяют два типа атрибутов:
- Атрибуты класса.
- Атрибуты экземпляров.
Атрибуты класса делятся среди всех экземпляров, относящихся к определенному классу. В то же время, атрибуты экземпляров – это собственность экземпляра.
Не забывайте о том, то «экземпляр» и «объект» – это синонимы.
Атрибуты объекта объявляются внутри какого-угодно метода. В то же время, атрибуты класса объявляются за пределами любого метода.
Более точно понять эту разницу можно с помощью такого примера.
class Car: # создаем атрибуты класса car_count = 0 # создаем методы класса def start(self, name, make, model): print("Двигатель заведен") self.name = name self.make = make self.model = model Car.car_count += 1
Здесь нами создается класс Car, имеющий один атрибут класса, который называется car_count, а также три атрибута объекта, именуемых name, make, model. Класс включает один метод start(), в который входит три атрибута экземпляров. В свою очередь, значения атрибутов экземпляров передаются в качестве аргументов методу start(). Внутри метода start, атрибут car_count увеличивается на единицу.
Необходимо отдельно обозначить то, что в рамках метода, атрибуты экземпляра ссылаются с помощью ключевика self, в то время как атрибуты класса ссылаются с помощью его названия.
Давайте попробуем создать объект класса Car, после чего вызовем метод start().
car_a = Car() car_a.start("Corrola", "Toyota", 2015) print(car_a.name) print(car_a.car_count)
В приведенном ранее скрипте мы вывели название атрибута экземпляра и атрибута класса car_count. В выдаче будет показано, что атрибут car_count будет иметь значение 1, как указано ниже.
Двигатель заведен
Corrola
1
Теперь давайте попробуем создать еще один объект класса Car и вызвать метод start().
car_b = Car() car_b.start("City", "Honda", 2013) print(car_b.name) print(car_b.car_count)
Сейчас если вы выведете значение атрибута car_count, то в выдаче увидите цифру 2. Почему это так? Дело в том, что атрибут car_count – это атрибут класса. Следовательно, он разделяется между экземплярами. Объект car_a увеличил значение до единицы, в то время как car_b увеличил значение еще раз таким образом, что результирующее значение получается 2. Выдача выглядит так.
Двигатель заведен
City
2