Java中的Delegate和Callback区别

18

我对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);
    }
}

回调函数和代理对象是相似的吗? (Are delegates and callbacks the same or similar?)?

如何实现另一个回调函数?


基于哪个“delegate”和“callback”的定义?Delegate的含义取决于上下文,例如Objective-C和C#中的含义显着不同。 - millimoose
例如: https://dev59.com/uXVC5IYBdhLWcg3wcwsm - pvllnspk
我只对Java和Objective C的上下文感兴趣(我想知道如何在纯Java中实现它)。 - pvllnspk
那个问题的被接受答案谈到了显然不是你的情况的C#。此外,你不能只是说“例如”。我的观点是,即使你非常、非常地迂腐,设计模式之间并没有真正的硬性和明确的区别。 - millimoose
我有点困惑,因为在开始学习Objective C时,我遇到了代理(delegate)的概念,它似乎非常类似于Java中的回调(callback) -> 因此我想感受一下它们之间的区别。 - pvllnspk
发现一个有趣的话题: https://dev59.com/AHNA5IYBdhLWcg3wUL9Y - pvllnspk
3个回答

37

这是一个回调函数。根据维基百科的定义:

在计算机编程中,回调指向被传递作为参数的可执行代码片段。

那么让我们看看这个可执行代码:

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 使用了 策略模式。需要注意两点:

  1. 调用 getHelp() 方法时没有传递可执行代码的引用。也就不是回调函数。
  2. MyObject.getHelp() 调用了 helpStrategy.getHelp(),但这个信息对于 MyObject 对象或者 getHelp() 调用者来说都不是公开接口中的一部分。这种信息隐藏是委托模式的一个典型特征。

还要注意一点,getHelp() 方法中没有 // do something 部分。当使用回调函数时,回调函数并不与对象的行为有关:它只以某种方式通知调用者,这就是为什么需要 // 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
        }
    }

6
我认为,“回调函数”是一个通用模式的名称,其中您提供调用的模块一种方法,以便该模块可以调用您的代码。C#委托或ObjC委托对象(这两个完全不同)或实现回调接口的Java类都是实现回调模式的不同平台特定方式。(它们本身也可以被认为是模式)。其他语言有更多或更少微妙不同的做法。
上述“委托”的概念也类似于策略模式,其中可以将委托视为一种策略。同样,访问者也是回调的一种类型。(访问者也是处理每个访问项目的策略。)
所有这些都是使用我直观的定义,可能对任何人都不适用,因为“回调”或“委托”都不是正式术语,如果没有引用先前在您的上下文中有效的定义,则在没有参考之下讨论它们没有多少意义。因此,询问定义的事实并没有多大意义,因为据我所知,没有权威的定义。即,回答此问题的其他答案可能会说出完全不同的内容。
我的建议是专注于设计的优点 - 是否实现了您需要的功能,是否没有引入紧密耦合等 - 而不是专注于语义的细节。当两种设计模式看起来相似时,它们可能同样适用于实现类似的目标。

1
你想要实现的是原始调用者和服务之间的双向通信,同时避免服务依赖于客户端。为了达到这个目标,你使用的模式通常取决于你所使用语言的限制。你可以使用函数指针、闭包或者如果你没有这些,回调对象(也可以看作是闭包)。
而且,同一个或非常相似的模式往往有许多不同的名称。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接