Каков предпочтительный способ организации обратных вызовов?

В моем проекте Android я определяю несколько обратных вызовов для обработки нажатий кнопок, событий подключения или событий пользовательского интерфейса, таких как Dilaog.onShow(). Для демонстрации я выбрал интерфейс Runnable, который должен быть запущен из некоторого кода Activity. С Java у меня есть разные способы выразить себя.

Один шаблон будет использовать анонимный класс

runOnUiThread(new Runnable() { 
    public void run() { 
        doSomething(); 
    }
});

private void doSomething() {
}

другое - определить внутренний закрытый класс, т.е.

private DoSomething implements Runnable {
    public void run() { 
        // do something; 
    }
}
...
runOnUiThread(new DoSomething());

еще один - использовать приватный член, вот так:

private final Runnable doSomething = new Runnable() {
    public void run() { 
        // do something; 
    }
}
...
runOnUiThread(doSomething);

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

private Runnable doSomething() { 
    return new Runnable() {
        public void run() { 
            // do something; 
        }
    }
}
...
runOnUiThread(doSomething());

Я не ищу аргументы вкуса или религиозных убеждений, но о возможности сопровождения кода и производительности. Я хотел бы получать советы и подсказки, которые могут помочь мне развить мои собственные предпочтения, возможно - различные предпочтения в соответствии с данным обстоятельством.

Спойлер:

Прогресс Java сделал этот вопрос устаревшим, см. Принятый ответ.

5 ответов

Решение

Сегодня, когда Java 8 почти доступна для Android, а Android Studio автоматически делает вид, что лямбды уже поддерживаются, решение анонимного класса (#1) кажется очевидным выбором:

развалился

расширенный

Я не верю, что есть какой-то идиоматический способ обработки обратных вызовов.

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

Если вы используете IDE, например Eclipse, вы можете выполнять все эти рефакторинги автоматически и безопасно.

Как @Manuel Silva и @Toby Champion, мне не нравятся анонимные внутренние классы. Их несколько трудно читать, они не очень "ОО" в том смысле, что их нельзя расширять, они не могут иметь DIP, сеттеры или что-то еще для настройки поведения и т. Д., И часто заканчивают тем, что нарушают принцип СУХОЙ когда вы добавляете один и тот же код в 27 разных местах.

Я обычно использую закрытые члены (ваш вариант № 3) или частную функцию (ваш четвертый стиль), обычно называемую getAsRunnable().

Я очень новичок в Android, но анонимные классы вызывают у меня тошноту, и кажется, что у вас есть альтернатива runOnUiThread: AsyncTask, обсуждалось здесь: runOnUIThread question

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

Другие вопросы по тегам