Предыдущие части:
В первых двух частях я объяснил, что такое объект. А в одном из выпусков приводил пример простейшей игры, где игрок сражается с несколькими монстрами. Там каждый монстр хранился в массиве в виде всего лишь одного числа – его здоровья. Теперь, в рамках ООП, я могу хранить в массиве не просто здоровье, а целого монстра в виде объекта.
Я сделаю ему следующие свойства: hp (здоровье), strength (cила), armor (крепость брони). А также я добавлю монстру метод move(), с помощью которого он будет двигаться. Всё это только для примера.
Теперь я с помощью цикла создам 10 монстров и занесу их всех в массив (на JavaScript):
Обратите внимание: монстр добавляется в массив с помощью monsters.push(), а откуда это взялось? Дело в том, что когда я создал пустой массив monsters, транслятор языка JavaScript скрытно создал не просто массив, а объект. И у этого объекта есть метод push(), который позволяет запихивать в него новые элементы, чем я и воспользовался. Метод push() есть не у каждого массива и не во всех языках, но это просто ещё один пример метода.
В прошлом выпуске я обещал проблем, ну и где они?
Я создал 10 объектов-монстров, и каждый объект содержит свойства: здоровье, силу, броню. Это нормально. Но каждый объект содержит ещё и метод move(), который создается заново каждый раз, когда создается новый объект. Значит, мы не только имеем 10 объектов, но также имеем 10 совершенно одинаковых методов move(), находящихся внутри этих объектов.
А это, во-первых, растрата памяти. Во-вторых, растрата процессорного времени. Ведь каждый раз, когда транслятор языка создает объект, ему нужно тратить и память, и время на создание метода. В-третьих, вы можете создавать объект-монстра и в других местах своей программы, и каждый раз придется описывать в нём метод move(), иначе он получится без метода и работать правильно не будет. Вот и проблема.
Ленивый программист в шоке от такого, и поэтому он придумывает классы. Вот как выглядит класс объекта-монстра (не использую конкретный язык, нужно лишь понимание концепции):
С виду это очень похоже на создание объекта. Можно легко различить свойства объекта hp, strength, armor, а также метод move(). Всё на своих местах, в чём же фишка?
Фишка в том, что класс является не объектом, а "чертежом" объекта. Сам по себе он инертен, ни на что не влияет, и нужен лишь для того, чтобы транслятор языка мог по этому чертежу создать объект.
Чтобы создать объект из этого класса, нужно написать так:
var monster = new Monster();
Ключевое слово здесь new.
Что делает транслятор языка, увидев его:
"Здесь написано new Monster, значит программист хочет создать новый объект класса Monster. Где-то должен быть чертеж с таким названием. Вот, нашел, class Monster. В нём указано, что надо создать у объекта свойства hp, strength, armor. Я cоздал объект с такими свойствами и сохранил указатель на него в переменную monster."
Вот, транслятор сам создал объект с нужными свойствами из класса. Стоп, а что насчет метода move()? Создался ли он в объекте? Нет, не создался. Но его теперь и не нужно создавать. Мы можем смело вызывать monster.move(), и вот как поступит транслятор языка:
"Здесь написано monster.move(), значит программист хочет у объекта monster вызвать метод move(). Но у этого объекта нет такого метода. Тогда я посмотрю в чертежах. Объект monster создан по чертежам класса Monster, а в этом классе описан метод move(). Значит, я вызову его."
Таким образом, все объекты класса Monster имеют доступ к одному и тому же методу move(), который описан в классе. Больше не нужно описывать этот метод в каждом объекте. Бонус – если требуется поменять метод move(), это нужно сделать всего один раз.
Теперь можно переписать цикл создания монстров с учетом класса:
Получилось отлично. Но ленивому программисту этого мало, у него опять проблемы.
Читайте дальше:
Подборка всех материалов по ООП: