Делегирование против обратного вызова в Java
У меня есть некоторое недоразумение относительно терминов делегатов и обратных вызовов в Java.
class MyDriver {
public static void main(String[] argv){
MyObject myObj = new MyObject();
// definition of HelpCallback omitted for brevity
myObj.getHelp(new HelpCallback () {
@Override
public void call(int result) {
System.out.println("Help Callback: "+result);
}
});
}
}
class MyObject {
public void getHelp(HelpCallback callback){
//do something
callback.call(OK);
}
}
Это вызов или делегирование (Являются ли делегаты и обратные вызовы одинаковыми или похожими?)?
Как реализовать другой?
Ответы
Ответ 1
Это обратный вызов. Согласно Википедии:
В компьютерном программировании обратный вызов является ссылкой на часть исполняемого кода, которая передается как аргумент другому коду.
Итак, посмотрим на исполняемый код:
public void getHelp(HelpCallback callback){
//do something
callback.call(OK);
}
Здесь аргумент callback
является ссылкой на объект типа HelpCallback
. Поскольку эта ссылка передается в качестве аргумента, это обратный вызов.
Пример делегирования
Делегирование выполняется внутри объекта - независимо от способа вызова метода. Если, например, переменная callback
не была аргументом, а скорее переменной экземпляра:
class MyDriver {
public static void main(String[] argv){
// definition of HelpStrategy omitted for brevity
MyObject myObj = new MyObject(new HelpStrategy() {
@Override
public void getHelp() {
System.out.println("Getting help!");
}
});
myObj.getHelp();
}
}
class MyObject {
private final HelpStrategy helpStrategy;
public MyObject(HelpStrategy helpStrategy) {
this.helpStrategy = helpStrategy;
}
public void getHelp(){
helpStrategy.getHelp();
}
}
... тогда это будет делегирование.
Здесь MyObject
использует шаблон стратегии . Следует отметить две вещи:
- Вызов
getHelp()
не включает передачу ссылки на исполняемый код. то есть это не обратный вызов.
- Тот факт, что
MyObject.getHelp()
вызывает helpStrategy.getHelp()
, не является очевидным из открытого интерфейса объекта MyObject
или из вызова getHelp()
. Этот вид скрытия информации является характерным для делегирования.
Также следует отметить отсутствие секции // do something
в методе getHelp()
. При использовании обратного вызова обратный вызов не делает ничего, что имеет отношение к поведению объекта: оно просто уведомляет вызывающего абонента каким-то образом, поэтому раздел // do something
был необходим. Однако при использовании делегирования фактическое поведение метода зависит от делегата - так что действительно мы могли бы нуждаться в обоих, поскольку они служат для различных целей:
public void getHelp(HelpCallback callback){
helpStrategy.getHelp(); // perform logic / behavior; "do something" as some might say
if(callback != null) {
callback.call(); // invoke the callback, to notify the caller of something
}
}
Ответ 2
Я бы сказал, что "обратный вызов" - это имя для общего шаблона, в котором вы предоставляете модуль, который вы вызываете, с тем, чтобы указанный модуль вызывал ваш код. Делегат С# или объект делегирования ObjC (эти два являются совершенно разными животными) или интерфейс Java-реализация-обратный вызов - это разные, специфичные для платформы способы реализации обратного шаблона. (Они также могут быть рассмотрены как модели.) Другие языки имеют более или менее тонко разные способы сделать это.
Вышеупомянутая концепция "делегата" также похожа на шаблон стратегии, где делегат можно рассматривать как один. Аналогичным образом, посетитель также является типом обратного вызова. (Посетитель также является стратегией для обработки каждого посещенного элемента.)
Все это использует определения, которые интуитивно понятны мне и могут быть не для кого-либо еще, потому что ни "обратный вызов", ни "делегирование" не являются формальными терминами, и нет смысла обсуждать их, не ссылаясь на их предыдущее определение, действительный в вашем контексте. Следовательно, не имеет смысла спрашивать, что такое определение, поскольку, насколько мне известно, нет авторитетного. Иными словами, тот факт, что другие ответы на этот вопрос, скорее всего, скажут что-то совершенно другое.
Моя рекомендация состояла бы в том, чтобы сосредоточиться на достоинствах вашего дизайна - будь то то, что вам нужно, не вводит жесткую связь и т.д., а не по мелочам семантики. Когда два шаблона проектирования кажутся похожими, они, вероятно, могут быть использованы для достижения одинаковых целей одинаково хорошо.
Ответ 3
То, что вы хотите достичь, - двунаправленная связь между исходным абонентом и службой, избегая при этом обслуживания, зависящего от клиента. Шаблон, который вы используете для этой цели, часто зависит от ограничений вашего языка. Вы используете указатели функций, замыкания или, если у вас нет ни одного из них, объекты обратного вызова (которые также могут рассматриваться как замыкания).
И тогда часто бывает много разных имен для одного и того же или очень похожего шаблона.