Основные принципы ООП
На прошлом занятии я познакомил вас с объектно-ориентированным программированием, и даже немного затронул один из принципов ООП - инкапсуляцию. Прежде чем двигаться дальше, я расскажу про оставшиеся базовые принципы ООП, которые помогут вам лучше разобраться в данной теме. Всего их четыре:
1. Абстракция
С помощью абстракции можно описать что-то сложное используя простые вещи. В Java в качестве абстракций используются классы и переменные, которые позволяют описать объекты реального мира, выделив существенные свойства, необходимые для решения конкретной задачи.
2. Инкапсуляция
Про инкапсуляцию я уже рассказывал, но на всякий случай повторюсь: это сокрытие переменных внутри класса с целью защиты их от безконтрольного изменения из вне. Все изменения данных, хранящихся в переменных экземпляра класса, производятся с помощью специальных публичных методов.
3. Наследование
Наследование позволяет описывать новые классы на основании уже существующих, или простыми словами - наследовать уже реализованный функционал. Это совершенно необходимо, когда приходится работать с похожими объектами, которые незначительно различаются в деталях. Таким образом не нужно дублировать существующий код, вместо этого можно просто отнаследоваться от класса. Про наследование детально проговорим на сегодняшнем уроке.
4. Полиморфизм
Полиморфизм это обработка одних и тех же данных разными способоми в зависимости от ситуации (переопределение методов), или же выполнение одних и тех же действий над разным набором данных (перегрузка методов). Про полиморфизм детально поговорим на сегодняшнем уроке.
Все базовые принципы ООП нужно обязательно запомнить, так как они пригодятся и на собеседовании и для дальнейшего понимания материала!
Наследование
Предположим что возникла необходимость создать несколько классов с очень похожим функционалом, который различается в каких-то незначительных деталях. Если решать данную задачу "в лоб", то в результате во всех написанных классах код будет практически одинаковым, что довольно плохо. Чем это может грозить? Любое новое изменение или исправление ошибки придётся делать сразу в нескольких классах, а не в одном месте. Это не только не удобно, но и потенциально создаёт возможности для новых проблем, в случае если разработчик забыл про какой-то класс в процессе внесения исправлений.
Лучшим решением будет создать базовый класс (суперкласс) с общей реализацией и отнаследовать от него другие классы (подклассы) в которых будет находиться уже частная реализация отличающихся частей функционала.
Чтобы отнаследоваться от существующего класса, необходимо использовать ключевое слово extends:
class <имя подкласса> extends <имя суперкласса> {
...
}
Чтобы лучше понять как работает наследование, разберём простейший пример - создадим несколько классов для графического редактора. И первый класс будет описывать некую фигуру, которую необходимо нарисовать. Фигуры бывают разные, но общее у них одно - координаты точки отрисовки, соответсвенно класс Figure будет собержать переменные x и y, а так же методы для работы с данными переменными:
package ru.akutepov;
public class Figure {
private int x;
private int y;
public Figure() {
}
public Figure(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
Предположим что наш графический редактор должен уметь рисовать окружности, соответсвенно нужен такой класс, который бы содержал координаты центра окружности и радиус. Если бы в Java небыло наследования, то пришлось бы в новом классе заново прописывать переменные x и y, а так же все методы, которые есть в классе Figure. А с наследованием всё гораздо проще:
package ru.akutepov;
public class Circle extends Figure {
private int radius;
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
}
Класс Circle наследуется от класса Figure, а значит имеет доступ ко всем переменным и методам класса Figure кроме приватных. Так как переменные x и y имеют модификатор private, то напрямую работать с ними из подкласса Circle нельзя, для этого есть методы getX(), setX(), getY() и setY(). Если необходим прямой доступ к переменной суперкласса, то можно использовать модификатор protected.
Сделаем ещё один подкласс для описания прямоугольника -