NOTE:
Я знаю, что это опасно близко ко многим другим вопросам. Тем не менее, я не видел, что это не относится конкретно к интерфейсу Android OnClickListener. Я спрашиваю в общем смысле.
Я понимаю разницу между созданием интерфейса через анонимный класс... a la:
private final Runnable runnable = new Runnable() {
@Override
public void run() {
draw();
}
};
... и расширения интерфейса.
public class ClassyClass implements Runnable {
...
//do other cool stuff here
...
@Override
public void run() {
draw();
}
...
//and more here
...
}
Но, кроме очевидных преимуществ интерфейсов, таких как OnClickListener
есть ли сильное преимущество для любого из этих вариантов?
Я бы подумал, что продление этого будет очевидным выбором, потому что вы уже создаете этот объект - никакого дублирования усилий. Это правильно?
Я прошу в общем смысле, но, поскольку я в настоящее время работаю с Runnable
, если он видит преимущество от любого варианта, который мне бы хотелось узнать.
Ну вот пример, который показывает основные отличия. Это немного надуманное, но это просто для иллюстрации.
Вот анонимная версия:
class PrintBuilder {
List<Runnable> printers = new LinkedList<>();
List<Runnable> get() {
return printers;
}
PrintBuilder add(final String line) {
printers.add(new Runnable() {
public void run() {
System.out.println(line);
}
});
return this;
}
}
Вот вложенная версия:
class PrintBuilder {
List<Printer> printers = new LinkedList<>();
PrintBuilder add(String line) {
printers.add(new Printer(line));
return this;
}
List<Printer> get() {
return printers;
}
static class Printer implements Runnable {
String line;
Printer(String line) {
this.line = line;
}
public void run() {
System.out.println(line);
}
}
}
Итак, вы можете видеть основные отличия:
В частности, в приведенном выше примере PrintBuilder просачивается до тех пор, пока не будут уничтожены внутренние объекты Runnable. Во втором примере класс Runnable статичен, поэтому у него нет этой проблемы.
Анонимному классу не нужны поля и конструкторы, потому что они неявные.
Анонимный класс объявляется там, где он был создан, и это может быть довольно разрушительным для макета охватывающего класса, если анонимный класс не очень короткий. С другой стороны, если анонимный класс короток, функционально-подобный синтаксис хорош.
Также все классы, как правило, растут, и по моему опыту это может превратиться в запах, когда анонимный класс становится слишком большим. Анонимные классы также намного сложнее реорганизовать в класс верхнего уровня.
Оба подхода действительны. Какой из них зависит от вашего использования:
Первый фрагмент определяет класс без имени, который реализует интерфейс Runnable (и создает этот анонимный класс). Второй определяет класс с именем, который также реализует интерфейс Runnable.
Там нет различий в терминах наследования и реализации интерфейса, кроме того, что второй класс имеет имя, а первый - нет.
Второй фрагмент позволяет нескольким классам создавать экземпляр реализации Runnable, тогда как первый определяет класс, который известен только из его охватывающего класса. Иногда один лучше, иногда другой.
this
как аргумент конструктора Printer.