Классы, методы и объекты

Как мы ранее говорили, класс - это шаблон нашего объекта. В нем мы описываем какие атрибуты могут быть у объекта и какие методы у него есть, с помощью которых мы можем взаимодействовать с объектом. Давайте посмотрим как создать наш класс:

# инициализация класса с названием Person. 
class Person
  # конструктор класса, а также его аргументы
  def initialize(name, age, address)
    # присвоение аргументов конструктора к аргументам объекта
    @name = name
    @age = age
    @address
  end
end

Названия классов следует всегда записывать в формате CamelCase (Каждое слово в названии пишется с заглавной буквы), например MagicBall.

Ранее при создании объекта вы встречали такое слово как new. Фактически, вызывая метод new у класса вы вызываете его конструктор. В конструкторе вы можете определить сколько угодно аргументов как и у любого другого метода, но сами по себе аргументы никакого отношения к самому классу не имеют, это просто набор параметров, которые можно передать при создании объекта. Для того, чтобы аргументы стали частью объекта, его атрибутами, необходимо создать эти самые атрибуты и прировнять их к аргументам. атрибуты объекта создаются с помощью знака @ перед названием самого атрибута. Сделав это, ваш объект при создании уже будет иметь какое-то собственное состояние.

Объекты

Давайте посмотрим как нам теперь создать наш объект на основе этого класса:

# Создаем объект класса Person, у которого атрибут name = Mike, age = 24, address = Moscow
mike = Person.new('Mike', 24, 'Moscow')
# Создаем объект класса Person, у которого атрибут name = Jane, age = 18, address = St. Petersburg
jane = Person.new('Jane', 18, 'St. Petersburg')

p mike # = Person(name = Mike, age = 24, address = Moscow)
p jane # = Person(name = Jane, age = 18, address = St. Petersburg)

Как мы видим при инспектировании данных объектов они имеют абсолютно отличающиеся данные внутри себя.

Методы

Хорошо, у нас есть класс, есть несколько экземпляров этого класса с отличающимися атрибутами. Но что мы можем с ним делать ? Все что душе угодно. Для начала давайте посмотрим как мы можем изменять состояние этих самых объектов

Для того, чтобы ваш код не превратился в кашу, создавайте новые классы в новых файлах, записанные в формате lower_case. Например наш класс Person, значит файл должен называться person.rb, класс называется MagicBall, значит файл называется magic_ball.rb и тд. Как использовать код из одного файла внутри другого ? Воспользуйтесь ключевым словом require или require_relative. Подробнее про это будет сказано в доп. материале.

Переменные и методы класса

Помимо наших обычных переменных объекта, которые мы объявляем с помощью @, существуют еще переменные класса, которые объявляются с помощью @@. Отличие от переменных объекта в том, что значение переменной объекта у каждого свое, оно является состоянием нашего объекта, в то время как переменная класса принадлежит целому классу и доступ к ней есть у любого объекта этого класса. Каждые раз создавая новый объект вы создаете, по большому счету, новый объект с новыми переменными. Если у объекта 3 переменные, вы создали 2 объекта, то фактически создаются 6 переменных, так как класс это в каком-то роде еще одна структруа данных. В случае с переменной класса она создается один раз и может быть переиспользована сразу в нескольких объектах. 1 переменная класса, 5 объектов, кол-во созданных переменных класса не меняется.

Методы класса точно так же как и переменные не завязаны на объекте, а являются частью класса. Записать метод класса можно следующим образом:

Запись через self.method или через class << self зависит вашего стиля кода или вашей команды. Старайтесь придерживаться правила: если у вас один метод класса, то лучше записать его с помощью self., если у вас несколько таких методов, то лучше вынести их во внутрь class << self, так как это позволяет нам поддерживать чистоту в и простоту в нашем коде.

Константы

Константы очень похожи по своей сути на переменные класса, но их концепция не завязана на ООП. Для объявления константы вам нужно записать ее как обычную переменную без @, но полностью заглавными буквами в формате snake_case. Константы можно определить и в обычном ruby файле без использования классов. Если в случае с переменными класса мы можем менять их значение без каких либо проблем, то в случае с константами при изменении значения мы увидим warning сообщение: warning: already initialized constant CONSTANT_NAME, при этом значение все равно поменяется.

К сожалению у нас нет возможности сделать константу неизменяемой, но у нас есть возможность сделать значение иммутабельным

Давайте посмотрим как это выглядит для класса:

Так же хорошей практикой является создавать отдельные классы для хранения однотипных констант

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

self

В прошлым примерах вы уже сталкивались с ключевым словом self, а теперь стоит разобрать что это такое. Мы привыкли уже создавать наши объекты, помоещать их в переменную6 а после передавать эту переменную куда-то еще (либо без переменной, сразу как значение передавать), но что если мы хотим получать доступ к объекту сразу изнутри этого самого объекта ? self позволяет нам внутри нашего класса обращаться к будущему объекту, который будет создан на основе этого класса. Звучит сложно, но с примером будет полегче

Также, self как мы рассматривали ранее, служит еще и для создания методов класса.

Задание animals

Внимание ! Это и последующие задания данного модуля с названием animals необходимо выполнять в одной и той же директории в корне модуля - 3_oop/animals

  • Реализовать класс Cat у которого есть такие атрибуты как name (имя) и weight (вес) (в граммах)

  • Добавьте константы в которых будет указан MIN_WEIGHT (минимальный вес) равный 1000грамм и MAX_WEIGHT (максимальный вес) равный 9000грамм.

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

  • Реализуйте следующие методы:

    • toilet - кот ходит в туалет и теряет 1 грамм своего веса.

    • voice - кот издает голос 'Meow' в консоль и теряет 1 грамм своего веса.

    • eat(food_grams) - кот принимает пишу. В аргументах он получает кол-во еды в граммах и пополняет вес на кол-во употребеленной еды.

    • drink(water_ml) - кот пьет воду. В аргументах он получает кол-во воды в миллилитрах и пополняет вес в зависимости от выпитой воды в соотношении 2мл/1г веса

    • status - если вес кота больше 9000г или меньше 1000г, то возвращается статус DEAD, в остальных случаях возвращается статус LIVE

  • реализуйте счетчик котов, который будет увеличиваться каждый раз при создании нового кота.

Попробуйте создать в файле main.rb несолько экземпляров вашего класса и повызывайте методы вашего кота, чтобы удостовериться, что кот жив.

Рекомендации:

  • Подумайте как лучше организовать хранение статусов кота.

  • не бойтесь вводить новые переменные по необходимости. Эта рекоммендация работает и для поледующих заданий.

Дополнительный материал

Last updated