Интерфейсы в механизме обратного вызова

Последнее обновление: 28.12.2015

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

Рассмотрим следующий пример:

public class EventsApp {

    public static void main(String[] args) {
        
        Button button = new Button(new ButtonClickHandler());
        button.click();
        button.click();
        button.click();
    }
}

class ButtonClickHandler implements EventHandler{
    
    public void execute(){
        
        System.out.println("Кнопка нажата!");
    }
}

interface EventHandler{
    
    void execute();
}

class Button{
    
    EventHandler handler;
    Button(EventHandler action){
        
        this.handler=action;
    }
    public void click(){
        
        handler.execute();
    }
}

Итак, здесь у нас определен класс Button, который в конструкторе принимает объект интерфейса EventHandler и в методе click (имитация нажатия) вызывает метод execute этого объекта.

Далее определяется реализация EventHandler в виде класса ButtonClickHandler. И в основной программе объект этого класса передается в конструктор Button. Таким образом, через конструктор мы устанавливаем обработчик нажатия кнопки. И при каждом вызове метода button.click() будет вызываться этот обработчик.

В итоге программа выведет на консоль следующий результат:

Кнопка нажата!
Кнопка нажата!
Кнопка нажата!

Но казалось бы, зачем нам выносить все действия в интерфейс, его реализовать, почему бы не написать проще сразу в классе Button:

class Button{
    
    public void click(){
        
        System.out.println("Кнопка нажата!");
    }
}

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

public class EventsApp {

    public static void main(String[] args) {
        
        Button tvButton = new Button(new EventHandler(){
              
            private boolean on = false;
            public void execute(){
                
                if(on) {
                    System.out.println("Телевизор выключен..");
                    on=false;
                }   
                else {
                    System.out.println("Телевизор включен!");
                    on=true;
                }
            }
        });
        
        Button printButton = new Button(new EventHandler(){
              
            public void execute(){
                
                System.out.println("Запущена печать на принтере...");
            }
        });
        
        tvButton.click();
        printButton.click();
        tvButton.click();
    }
}

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

В итоге консоль выведет нам следующий результат:

Телевизор включен!
Запущена печать на принтере...
Телевизор выключен..

И в завершении надо сказать, что интерфейсы в данном качестве особенно широко используются в различных графических API - AWT, Swing, JavaFX, где обработка событий объектов - элементов графического интерфейса особенно актуальна.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850