Java-эквивалент делегатов Какао / Неофициальные протоколы Objective-C?
-
06-07-2019 - |
Вопрос
Что такое Java-эквивалент делегатов Какао?
(я понимаю, что я могу передать интерфейс в класс и заставить этот класс вызывать соответствующие методы, но мне интересно, есть ли другой способ достичь чего-то более близкого к неофициальным протоколам Cocoa / Objective-C) р>
Решение
Короткий ответ: в Java нет ничего более близкого, чем хотелось бы, но есть альтернативы. Шаблон делегата не сложно реализовать, просто он не так удобен, как при использовании Objective-C.
Причина "неофициальных протоколов" Работа в Objective-C объясняется тем, что язык поддерживает категории , которые позволяют добавлять методы к существующим классам, не разбивая их на подклассы или даже не имея доступа к исходному коду. Таким образом, большинство неформальных протоколов являются категорией на NSObject. Это явно невозможно в Java.
Objective-C 2.0 выбирает методы @optional протокола, который является намного более чистой абстракцией и предпочтителен для нового кода, но еще дальше от аналога в Java.
Честно говоря, наиболее гибкий подход заключается в определении протокола делегата, а затем в классах реализуют все методы. (В современных IDE, таких как Eclipse, это тривиально.) Многие интерфейсы Java имеют сопутствующий класс адаптера, и это общий подход, при котором пользователю не требуется реализовывать много пустых методов, но он ограничивает наследование, что делает дизайн кода негибким , (Джош Блох рассматривает это в своей книге «Эффективная Java».) Я бы предложил сначала предоставить только интерфейс, а затем добавить адаптер, если это действительно необходимо.
Что бы вы ни делали, не добавляйте UnsupportedOperationException
для " не реализованного " методы. Это заставляет делегирующий класс обрабатывать исключения для методов, которые должны быть необязательными. Правильный подход - реализовать метод, который ничего не делает, возвращает значение по умолчанию и т. Д. Эти значения должны быть хорошо документированы для методов, которые не имеют возвращаемого типа void.
Другие советы
Лучший аналог неофициального протокола, о котором я могу подумать, - это интерфейс, который также имеет класс адаптера, позволяющий разработчикам избегать реализации каждого метода.
public class MyClass {
private MyClassDelegate delegate;
public MyClass () {
}
// do interesting stuff
void setDelegate(MyClassDelegate delegate) {
this.delegate = delegate;
}
interface MyClassDelegate {
void aboutToDoSomethingAwesome();
void didSomethingAwesome();
}
class MyClassDelegateAdapter implements MyClassDelegate {
@Override
public void aboutToDoSomethingAwesome() {
/* do nothing */
}
@Override
public void didSomethingAwesome() {
/* do nothing */
}
}
}
Тогда кто-то может прийти и просто реализовать то, что ему небезразлично:
class AwesomeDelegate extends MyClassDelegateAdapter {
@Override
public void didSomethingAwesome() {
System.out.println("Yeah!");
}
}
Либо это, либо чистое отражение, называющее "известным" методы. Но это безумие.
Ничто не мешает вам использовать шаблон делегата в ваших объектах Java (это просто не часто используемый шаблон в JDK, как в Какао). Просто имейте ивару делегат
типа, который соответствует вашему интерфейсу WhwhatDelegate
, а затем в методах вашего экземпляра, которым вы хотите делегировать, перенаправьте вызов метода на объект делегата, если он существует , Возможно, в конечном итоге вы получите нечто, похожее на это , за исключением Java вместо Obj-C.
Что касается необязательных интерфейсов, это будет сложнее. Я бы предложил объявить интерфейс, объявить абстрактный класс, который реализует необязательные методы как пустые методы, а затем создать подкласс класса абстрактного класса, переопределяя необязательные методы, которые вы хотите реализовать в данном конкретном объекте. Здесь существует потенциально серьезное ограничение из-за отсутствия множественного наследования в Java, но это настолько близко, насколько я могу придумать.