
Программирование — довольно сложная штука, и, поэтому, его хорошо учить на наглядных примерах.
А что может быть наглядней котофея? :-)) Поэтому, попробуем рассмотреть кота через объектно-ориентированное программирование (ООП) и его классы.
Итак, что же представляет собой кот с точки зрения ООП?
Статья, в большей степени, будет интересна начинающим.
Что такое классы в ООП и зачем они?
Но, для начала, давайте поймём, что скрывается за понятием класса в рамках ООП (это поможет нам понять ту информацию, которая будет ниже).Если сказать упрощённо, то класс — это такой своеобразный шаблон, по которому создаются объекты определённого типа.
Класс может иметь определённые поля, например, если это класс «человек», то он может иметь такие поля как: возраст, рост, пол, и т.д.
Кроме полей, класс может иметь определенные методы, описывающие поведение его объектов. Например, человек может ходить, говорить, спать на диване (вместо работы (:-) и т.д.
Если сказать более обобщённо, то класс нужен, для упаковки данных и некой логики в рамках одного компонента; также, подобная компоновка позволяет реализовать многократное использование кода.
Скажем, в примере выше, мы можем создать много людей, с одним и тем же поведением, которые вместо того, чтобы ходить на работу, будут желать только лежать на диване и ничего не делать :-)
Также, методы и поля класса имеют так называемые «модификаторы доступа», которые показывают, кому доступны для просмотра и использования поля и методы класса.
Среди модификаторов доступа можно назвать такие как:
public:
он показывает, что доступ возможен всем другим классам;private:
используется для скрытия реализации, чтобы внешние пользователи не могли сломать логику.
Например, возраст человека может быть вычислен каким-то способом, недоступным снаружи, но сам результат вычислений, — собственно число, символизирующее возраст — можно сделать доступным по запросу, с помощью «геттера».
В теории, что могло бы быть, если бы возраст человека был доступен для изменения любому: например, его максимальное значение 100, а кто угодно мог бы его поставить на 100500 (что вряд ли похоже на правду), кроме того, мы совершенно не знаем, кто и где это сделал…
Таким образом, геттеры и сеттеры дают большую гибкость, так как мы можем в любой момент изменить внутреннюю реализацию: пользователь получает только результат вычислений с помощью геттера, а как оно там внутри вычисляется — мы можем в любой момент изменить.
Кроме того, как уже было сказано, они дают безопасность, реализуя «инкапсуляцию» — один из базовых принципов ООП (своими данными должен управлять сам объект).
Также, неотъемлемым элементом понятия класса является понятие «конструктора» — специального метода, который вызывается во время создания объекта и служит для того, чтобы поля объекта были проинициализированы, а сам объект был создан в корректном состоянии (например, у обычного человека не может быть 4 ноги, и у него обязательно должно быть имя).
При этом, имя конструктора должно совпадать с именем класса, он не будет иметь никаких возвращаемых значений, и у класса может быть несколько конструкторов с разным количеством параметров (мы можем создать только человека с именем, человека с именем и возрастом и т.д.).
Итак, после того, как мы немножко ознакомились с понятием классов, попробуем спроектировать свой собственный класс Cat.
Generation Next Cat
Предположим, что наш кот будет иметь три ключевые характеристики (которые и будут представлять собой поля класса):- как зовут кота (nickname);
- уровень его усталости или, если хотите, энергичности (power);
- настроение (feeling).
String nickname
), а также проинициализируем и другие поля:
Разберём код выше: как можно видеть, мы снабдили все три переменные — имя, энергетику и настроение кота модификаторами
private
, то есть они недоступны извне класса.Прямо под ними можно видеть конструктор класса, с передаваемым ему именем, и инициализацией других полей.
И вот тут, кстати, у наблюдательных читателей, наверняка возникнет вопрос: а почему мы передаём только имя (String nickname
) в конструктор? По идее, мы должны были в скобках передавать все три поля?
Абсолютно верно, можно было передавать все три поля в скобках, но тут был выбран вариант попроще, так как имя является обязательным, в то время как остальные два поля уже имеют значения по умолчанию и, при создании новых котов, просто можно их называть, давая имя, в то время как остальные параметры «пускай остаются по умолчанию».
Таким образом:
- всё передавать в скобках конструктору следует, если не существует значений по умолчанию, поля обязательны и требуется некая пользовательская конфигурация для всех полей;
- в противовес первому варианту, некоторые поля можно оставить внутри конструктора, не передавая в скобках, если они редко меняются, и есть для них значения по умолчанию.
Говоря про конструктор, возникает интересный вопрос, а что было бы, если бы мы не определяли конструктор в явном виде?
Очень просто: java сама создаст пустой конструктор по умолчанию, где все поля останутся равными
null
или 0
(что для кота будет явным багом — " абстрактный кот в вакууме" нам не интересен, нам нужен только «конкретно этот рыжий Барсик»).Теперь, ещё один любопытный момент: как можно видеть в коде выше, в конструкторе все три поля имеют спереди ключевое слово this
с точкой в конце.
Что это значит: это ссылка на текущий объект класса. То есть, мы здесь говорим (через точку), что текущему объекту класса будут присваиваться поля.
А можно ли обойтись без этого ключевого слова
this
?Можно и так, но, только в том случае, если имя поля и параметр, передаваемый в скобках, не совпадают по названию:

Что это означает, если написать «человеческими словами»: «при создании объекта, полю
nickname
— присвоить ту строку, которую передаст пользователь».Тем не менее, так делать не рекомендуется, так как это не очень наглядно и использование ключевого слова
this
выглядит более понятным.Также, создадим несколько методов, которые характеризует кота:
- он сможет мурлыкать (
purr()
); - спать определённое количество часов и восстанавливать за счёт этого свои силы (
sleep(into hours)
); - изменять своё настроение в зависимости от восстановленных сил (
updateFeeling()
).
getNickname()
;getPower()
;getFeeling();
enum
, который позволяет хранить константные значения.Применение такого класса более безопасно, чем явное задание их с помощью, например, строк, так как, например, легко можно допустить опечатку.
Посмотрим, что у нас получилось:

Кстати говоря, многие знают класс
enum
только как средство хранения константных значений, однако, что, если я скажу вам, что в нём можно хранить ещё и методы (и не только — об этом ниже), чтобы наши константы могли что-либо делать?Например, пускай эмоции выводят смайлики и тогда это будет выглядеть вот так:

Как можно видеть, рядом с константами в скобках находятся параметры. В качестве таких параметров можно передавать:
- Строки;
- Числа;
- Объекты.
enum
(в нашем примере это строка):
А использовать такие методы можно, например, следующим образом:

К слову, как вы могли догадаться, раз здесь в коде
enum
присутствует конструктор, то никто не мешает нам создать несколько полей, например, типа: int
, string
и объявить их в конструкторе!Таким образом, можно передавать уже не один параметр, а несколько!
Что это даёт: у нас образуется своеобразная небольшая база данных, к которой можно обращаться и забирать оттуда информацию:

Использовать хранящиеся данные можно следующим образом:

Ну и напоследок, попробуем смоделировать поведение кота, в разных ситуациях, при этом, избежав множественных циклов
if-else
, для чего используем паттерн «Состояние»: создадим ряд классов, реализующих общий интерфейс и переопределяющих его методы — каждый класс по-своему:
Как можно видеть, в двух кусках кода выше используются сеттеры, которых у нас изначально не было:

— их нужно добавить в основной код кота, чтобы не было ошибки:
