Курс "Объектно-ориентированное программирование"
  • Главная
  • 1 семестр (осень 2021)
    • Видео
    • Конспект лекций
      • Лекция 1
      • Лекция 2
      • Лекция 3
      • Лекция 4
      • Лекция 5
      • Лекция 6
      • Лекция 7
      • Лекция 8
      • Лекция 9
      • Лекция 10
      • Лекция 11
      • Лекция 12
      • Лекция 13
      • Лекция 14
      • Лекция 15
    • Лабораторные работы
      • Лабораторная работа 1
        • 1. Установка программного обеспечения, создание и запуск проекта
        • 2. Основы синатксиса Java
        • Задание на лабораторную работу
      • Лабораторная работа 2
        • Синтаксис создания классов
        • Задание на лабораторную работу
      • Лабораторная работа 3
        • Инкапсуляция
        • Язык моделирования UML
        • Задание на лабораторную работу
      • Лабораторная работа 4
        • Наследование и композиция
        • Наследование и композиция в UML
        • Задание на лабораторную работу
      • Лабораторная работа 5
        • Задание на лабораторную работу
      • Лабораторная работа 6
        • Абстрактные классы и интерфейсы в UML
        • Задание на лабораторную работу
  • 2 семестр (весна 2022)
    • Конспект лекций
      • Лекция 1-2
      • Лекция 3-4
      • Лекция 5
      • Лекция 6
      • Лекция 7-8
      • Лекция 9
      • Лекция 10
      • Лекция 11-12
      • Лекция 13-14
      • Лекция 15
  • Архив
    • Лекция 2
    • Архив
      • Заметки по абстракции
      • Конспект лекций
        • 1. Принцип Separation of Concerns, контроллер и представление
        • 2. Паттерн MVC
        • 3. Клиент-серверная архитектура. Создание простой RESTful веб-службы с помощью Spring Boot.
        • 4. Внедрение зависимостей (Dependency Injection)
        • 5. Интеграция приложения с СУБД
        • 6. Фреймворк Spring MVC
        • 7. Работа со Spring Security, часть 1
        • 8. Работа со Spring Security, часть 2
        • 9. Развертывание приложения в Heroku
      • Заочники (осень 2022)
      • Архив
        • Лекции
          • Draft
            • 5. Абстрактные классы и интерфейсы. Механизм обратного вызова
            • 6. Анонимные классы
          • Блок лекций 1
            • Дополнительные задания и литература
            • 1. Базовые сведения об ООП
            • 1. Обобщенные типы. Автоупаковка и автораспаковка.
            • 2. Знакомство с языком Java
          • Блок лекций 2
            • 5. Абстрактные классы и интерфейсы. Механизм обратного вызова.
            • 6. Анонимные объекты, классы, методы. Лямбда-выражения.
            • 7. Аргументы переменной длины. Принцип абстракции. Дополнительные принципы ООП.
          • Блок лекций 3
            • 2. Коллекции объектов.
            • 3. Паттерн Итератор. Компараторы. Потоки в Java (Streams API)
          • Блок лекций 4
            • 1. Исключения в Java. Обработка исключений.
          • Блок лекций 5
            • Статические поля и методы
            • Вложенные и внутренние классы
            • Перечисления
          • Блок лекций 6
            • 2. Интеграция приложения с СУБД
        • Лабораторные работы
          • 2. Основы синтаксиса
            • Python
            • C#
          • Лабораторная работа 3
            • 1. Инкапсуляция
            • 2. Перегрузка методов
            • Задание на лабораторную работу
            • Теоретические вопросы
          • Лабораторная работа 4
            • Задание на лабораторную работу
            • Теоретические вопросы
          • Лабораторная работа 6
            • Задание на лабораторную работу
            • Теоретические вопросы
          • Лабораторная работа 7
            • Задание на лабораторную работу
            • Теоретические вопросы
          • Лабораторная работа 8
          • Лабораторная работа 9
          • Лабораторная работа 10
            • Задание на лабораторную работу
          • Лабораторная работа 11
            • Задание на лабораторную работу
          • Лабораторная работа 12
            • Пример выполнения лабораторной работы
            • Задание на лабораторную работу
        • Практические работы
          • Практическая работа 1
          • Практическая работа 2
        • Материалы по Java Spring
          • 1. Клиент-серверная архитектура. Создание простой RESTful веб-службы с помощью Spring Boot.
          • 4. Работа со Spring MVC, часть 1
          • 5. Работа со Spring MVC, часть 2
      • Конспект лекций
        • 1. История развития языков программирования
        • 2. Базовые термины ООП
        • 3. Понятие класса и объекта
        • 4. Создание объектов. Конструктор.
        • 5. Основные принципы ООП. Инкапсуляция.
        • 6. Перегрузка методов
        • 7. Повторное использование кода. Композиция и наследование
        • 8. Полиморфизм
        • 9. Абстрактные классы и интерфейсы
        • 10. Анонимные классы, интерфейсы, методы. Лямбда-выражения
        • 11. Принцип абстракции. Дополнительные принципы ООП
        • 12. Обобщенные типы. Автоупаковка и автораспаковка
        • 13. Коллекции
        • 14. Паттерн "Итератор". Компараторы. Фреймворк Streams API.
        • 15. Исключения в Java. Обработка исключений
        • 16. Принципы разработки графического интерфейса. Фреймворк JavaFX
        • 17. События в JavaFX
        • 20. Перечисления
      • Лабораторные работы
        • Лабораторная работа 2
          • 1. Синтаксис создания классов
          • 2. Язык моделирования UML
          • Задание на лабораторную работу
          • Теоретические вопросы
        • Лабораторная работа 3
          • 1. Инкапсуляция
          • 2. Перегрузка методов
          • Задание на лабораторную работу
        • Лабораторная работа 4
          • Наследование и композиция
          • Наследование и композиция в диаграмме классов UML
          • Задание на лабораторную работу
        • Лабораторная работа 5
          • Задание на лабораторную работу
          • Теоретические вопросы
        • Лабораторная работа 6
          • Задание (старое)
          • Теоретические вопросы
        • Лабораторная работа 8
          • Задание на лабораторную работу
        • Лабораторная работа 9
          • Задание на лабораторную работу
      • Видеолекции
      • Видеолекции
Powered by GitBook
On this page
  • Абстрактный класс
  • Интерфейс
  • Реализация механизма обратного вызова с помощью интерфейсов

Was this helpful?

Export as PDF
  1. Архив
  2. Архив
  3. Архив
  4. Лекции
  5. Draft

5. Абстрактные классы и интерфейсы. Механизм обратного вызова

Интерфейсы и абстрактные классы улучшают структуру кода и способствуют отделению интерфейса от реализации.

Абстрактный класс

Вернемся к примеру с классами фигур

class Shape {
    public String draw() {
        return null;
    }

    public String erase() {
        return null;
    }
}
    
class Circle extends Shape {
    @Override
    public String draw() {
        return "Рисуем круг";
    }

    @Override
    public String erase() {
        return "Стираем круг";
    }
}

Методы базового класса Shape всегда были "фиктивными". Попытка вызова метода из класса Shape привела бы к ошибке в программе. Такая логика написания кода связана с тем, что класс Shape нам нужен лишь для того, чтобы определить общий интерфейс всех классов, производных от него, а уже производные классы переопределяли эти методы и реализовывали их по-своему.

Если в программе определяется такой абстрактный базовый класс вроде Shape, создание объектов такого класса практически всегда бессмысленно. Абстрактный класс создается для работы с набором классов через общий интерфейс. А если Shape только выражает интерфейс, а создание объектов такого класса не имеет смысла, лучше всего запретить пользователю создавать такие объекты, так как попытка работать с этим классом приведет к ошибке в программе.

В языке Java для решения подобных задач применяются абстрактные методы. Абстрактный метод является незавершенным, он состоит только из объявления и не имеет тела. Приведем пример абстрактного метода:

abstract Shape draw();

Класс, содержащий один или более абстрактных метода, называется абстрактным классом. Такие классы также должны помечаться ключевым словом abstract (в противном случае, компилятор выдает сообщение об ошибке)

Компилятор запрещает создавать объекты абстрактного класса.

Если вы объявите не абстрактный класс, производный от абстрактного класса, то вы обязаны переопределить все абстрактные методы базового класса. Если это не будет сделано, то производный класс будет считаться абстрактным, и компилятор заставит пометить новый класс ключевым словом abstract.

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

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

Создавать абстрактные классы необходимо, так как они подчеркивают абстрактность класса, а также сообщают и пользователю класса и компилятору, как следует с ним обходиться. Кроме этого, абстрактные классы играют полезную роль при рефакторинге программ, потому что они позволяют легко перемещать общие методы вверх по иерархии классов.

Интерфейс

Ключевое слово interface становится следующим шагом на пути к абстракции. Ключевое слово interface используется для создания классов, вообще не имеющих реализации. Создатель интерфейса определяет имена методов, списки аргументов и типы возвращаемых значений, но не тела методов. Интерфейс описывает форму, но не реализацию.

Ключевое слово interface фактически означает "Именно так должны выглядеть все классы, которые реализуют данный интерфейс". Поэтому любой код, использующий конкретный интерфейс, знает только то, какие методы вызываются для этого интерфейса, но не более того. Интерфейс определяет своего рода "протокол взаимодействия" между классами.

Кроме этого, в отличие от абстрактного класса, интерфейс позволяет реализовать своего рода, множественное наследование.

Чтобы создать интерфейс, используйте ключевое слово interface вместо class. Как и в случае с классами, перед ключевым словом interface указывается модификатор доступа (public, protected и так далее). Интерфейс также может содержать поля, они автоматически являются статическими (static) константами (final).

Для создания класса, реализующего определенный интерфейс (или несколько интерфейсов), используется ключевое слово implements. Фактически это означает "интерфейс определяет форму, а здесь будет показано, как это работает".

В классе, который реализует интерфейс, реализуемые методы должны быть объявлены как public.

Неважно, приводите ли вы преобразование к "обычному" классу с именем Shape, к абстрактному классу Shape или к интерфейсу Shape - действие будет одинаковым.

Когда метод работает с классом вместо интерфейса, мы ограничены использованием базового класса и его подклассами. Это исключает возможность использовать метод для класса, который не входит в эту иерархию. Интерфейс, в значительной степени, ослабляет это ограничение. В результате код становится более универсальным.

Применение интерфейсных ссылок

В Java допускается объявлять переменные ссылочного интерфейсного типа, то есть переменные, хранящие ссылки на объекты классов, которые реализуют определенный интерфейс.

Такая переменная может ссылаться на любой объект класса, который реализует интерфейс. При вызове метода для объекта по интерфейсной ссылке выполняется вариант этого метода, реализованный в классе данного объекта. Этот механизм аналогичен тому, когда ссылочная переменная суперкласса ссылается на объект подкласса.

Реализация нескольких интерфейсов

Так как интерфейс по определению не имеет реализации, нет ничего, что могло бы помешать совмещению нескольких интерфейсов. При объявлении класса, который реализует несколько интерфейсов, имена интерфейсов перечисляются вслед за ключевым словом implements и разделяется запятыми.

Реализация механизма обратного вызова с помощью интерфейсов

Механизм обратного вызова (callback) является ключевым в программировании. При обратном вызове, программист задает действия, которые должны выполняться всякий раз, когда происходит некоторое событие. Например, можно задать действие, которое должно быть выполнено после нажатия на кнопку или при выборе определенного пункта меню.

Приведем небольшой пример. В стандартной библиотеке классов Java нам доступен класс javax.swing.Timer, который используется для отсчета интервалов времени.

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

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

Разумеется, таймер должен знать, какой метод объекта он должен вызвать и этот метод в объекте гарантированно должен быть реализован. Для этого таймеру нужно указать объект класса, который реализует интерфейс ActionListener. Этот интерфейс входит в состав стандартной библиотеки и выглядит следующим образом

public interface ActionListener extends EventListener {
    public void actionPerformed(ActionEvent e);
}

По истечении заданного интервала времени таймер вызывает метод actionPerformed() и передает ему объект класса Event (класс Event описывает событие в Java):

Как мы видим, конструктор класса Timer запрашивает задержку и объект, у которого будет вызван метод actionPerformed.

Создадим класс, который будет реализовывать интерфейс ActionListener

Как мы видим, данный класс ничего кроме реализации интерфейса не делает. То есть он нужен только для одной цели - он содержит метод, который будет вызван таймером после задержки. Такие классы и их объекты называют слушателями. Слушатель - это объект, который, как бы, "слушает" события, которые происходят с другим объектом. И когда это "слушаемое" событие происходит, вызывается указанный в интерфейсе метод этого объекта.

Создадим слушатель MessageDialogPoster и передадим этот объект таймеру

Запустим приложение и посмотрим на результат.

Обратите внимание, что метод actionPerformed принимает на вход объект класса ActionEvent. При вызове метода actionPerformed(), таймер передает в метод объект класса ActionEvent, который содержит различную информацию о событии. Таким образом, мы можем запрограммировать те или иные действия, в зависимости от параметров события.

Рассмотрим еще один пример, на этот раз будем использовать кнопку. Создадим объект окна, объект кнопки и добавим кнопку в окно.

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

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

В данном случае нас интересует метод addActionListener(), который принимает объект слушателя, который реализует интерфейс ActionListener

С помощью этого метода, мы передаем кнопке объект класса MouseClickHandler. Когда произойдет какое-то событие, кнопка возьмет этот переданный объект и вызовет метод actionPerformed() этого объекта.

Запустим приложение и нажмем кнопку.

Та

PreviousDraftNext6. Анонимные классы

Last updated 5 years ago

Was this helpful?