ООП - история лени

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

Видеоверсия Презентация

История происхождения

Программы делали достаточно давно. Сначала их делали учёные для произведения сложных и нудных вычислений, которые необходимы были для их исследований. Потом начали появляться программы посложнее и поинтереснее - о компьютерах заговорили не только как о калькуляторах, но и как о машинах, способных делать много разных интересных вещей и сразу.

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

Структуры

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

   [a]
  [$] [c]   [d]
     [S]     [r]
[T]      [f]
    [v]

Скорость доступа к таким переменным была маленькая…

Программистам требовалось описывать какое-то состояние чего-либо, например ракеты в какой-нибудь игре, с помощью большого количества переменных - направление киля, скорость и направление ветра, масса, мощьность головки и т. д. Но ракет на складе много, значит нужен массив. Для вычисления направления киля 15 ракет для достижения всеми ими определённой точки нужно, допустим, 3 параметра - скорость ветра, точка запуска, скорость движения ракеты. Для каждой ракеты делать переменные Vwind_1, Vwind_2Vwind_15 никто не хотел, поэтому они хранились в массиве, где индекс был номером ракеты: Vwind_i = [10, 200, 35, 47, ...]. Такой массив был относительно быстрее и мог хранить много значений в одной переменной.

[v:12, 34, 56]   [s:2, 346, 633, 87]
   [r:45, 6916, 7, 473, 3258, ... ]

Скорость досутпа была чуть выше, но всё равно все алгоритмы страдали от того, что данные одной ракеты разбросаны не только по памяти, но и по разным переменным, название каждой нужно было знать и помнить её смысл. А если одна из ракет взрывалась? А если игрок поставил турель и она постоянно пускает ракеты - это же ужас! Нужно следить чтобы во всех массивах не просто было одинаковое количество элементов, но и каждый элемент соответствовал элементам в других массивах, чтобы не получалось ракет-мутантов, которые только что вылетили из ствола, а уже имеют скорость света.

Решением стали структуры - новый тип данных, который состоял из нескольких переменных (свойств), хранящихся в памяти друг рядом с другом. Доступ к значениям этих переменных осуществлялся так же как к элементам массива.

Получалось что-то такое:

[Vel_x,Vel_y,Mass,X,Y]

Такой тип данных прекрасно хранится в массиве, так как каждое свойство имеет свой размер, значит можно узнать и размер всей структуры.

[[Vel_x,Vel_y,Mass,X,Y], [Vel_x,Vel_y,Mass,X,Y], ...]

А самое главное - теперь всё хранится в одном месте - не нужно думать о нескольких массивах из которых надо удалять элементы.

Так объекты обзавелись свойствами.

Не повторяй свой код!

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

Но полки нужно как-то передвигать на поле. Для этого для каждого типа техники и солдата были написаны алгоритмы, передвигающие объект на поле. Получилось много функций, делающих по сути одно и тоже - изменяющих координаты объектов на поле. Тогда было решено соединить их все в одну функцию move, но поскольку объектов много и все разные, внутри этой функции стало слишком много конструкций if ... else, просто определяющих скорость машины или человека. Логично не определять скорость в функции каждый раз, а хранить её где-то внутри самого объекта, например в поле max_speed.

Так появилось два очень важное понятие в ООП - базовые свойства. Функция move могла принимать на вход любой объект, который имел 3 базовых для этой функции свойства: X, Y и максимальную скорость.

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

“А давайте вообще всё хранить в одном месте”

До этого программисты уже поняли, что хранить функцию move в глобальной области видимости - не хорошо, но и в модуле её хранить как-то не очень приятно.

Теперь у наших ленивых героев в голове появилась гениальная идея: “А давайте будем хранить функцию move внутри структур как static-свойство!”

Эти static-свойства, являющиеся функциями, теперь называются методами. А структура с методами называется классом.

Дурная наследственность…

Ещё через какое-то время программистам дали задачу - реализовать танкам повороты, то есть перед тем, как ехать к какой-то точке им нужно было направиться к этой точке передом.

Ещё одна интереснейшая мысль спустилась на головы людей: “Давайте даже сделаем лучше, сделаем один класс Movable, который будет иметь X, Y, V и move и заставим остальные классы так же иметь эти свойства! А для Tank просто сделаем свою move, которая будет сначала поварачиваться, а потом уже и двигаться”.

Таким образом появились понятия предок - класс Movable - и наследник. Смысл был в том, чтобы сделать один функционал для всех и потом наследовать его, то есть использовать один и тот же, не копируя ни строчки кода. А для тех, кому нужны какие-то изменения - создавать новый метод или свойство.

Потом оказалось, что не всегда можно сразу всем задать один и тот же способ передвижения, но код был заточен на то, что все классы являются наследниками Movable. Программисты стали писать, что все классы, с которыми работает этот код должны бы быть наследниками Movable. Такой класс, к которому “должны бы наследоваться другие” назвали интерфейсом. А саму формулировку “должно бы наследоваться” заменили на “должно реализовывать интерфейс”.