8. Углубленное изучение ООП (Java. Базовый курс)


Канал в Telegram

8. Углубленное изучение ООП (Java. Базовый курс)


Дата публикации 15.03.2021



Углубленное изучение объектно-ориентированного программирования

Основные принципы ООП

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

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.

Сделаем ещё один подкласс для описания прямоугольника -