76

我来自 JavaScript,其中回调非常简单。我正在尝试将它们实现到 JAVA 中,但没有成功。

我有一个父类:

import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
    ExecutorService workers = Executors.newFixedThreadPool(10);
    private ServerConnections serverConnectionHandler;

    public Server(int _address) {
        System.out.println("Starting Server...");
        serverConnectionHandler = new ServerConnections(_address);

        serverConnectionHandler.newConnection = function(Socket _socket) {
            System.out.println("A function of my child class was called.");
        };

        workers.execute(serverConnectionHandler);

        System.out.println("Do something else...");
    }
}

然后我有一个子类,它是从父类调用的:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ServerConnections implements Runnable {
    private int serverPort;
    private ServerSocket mainSocket;

    public ServerConnections(int _serverPort) {
        serverPort = _serverPort;
    }

    @Override
    public void run() {
        System.out.println("Starting Server Thread...");

        try {
            mainSocket = new ServerSocket(serverPort);

            while (true) {
                newConnection(mainSocket.accept());
            }
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void newConnection(Socket _socket) {

    }
}

什么是正确的实施方式

serverConnectionHandler.newConnection = function(Socket _socket) {
    System.out.println("A function of my child class was called.");
};

部分,在 Parent 类中,这显然是不正确的?

4

5 回答 5

137

定义一个接口,并在接收回调的类中实现它。

请注意您的情况下的多线程。

来自http://cleancodedevelopment-qualityseal.blogspot.com.br/2012/10/understanding-callbacks-with-java.html的代码示例

interface CallBack {                   

//declare an interface with the callback methods, 
//so you can use on more than one class and just 
//refer to the interface

    void methodToCallBack();
}

class CallBackImpl implements CallBack {          

//class that implements the method to callback defined 
//in the interface

    public void methodToCallBack() {
        System.out.println("I've been called back");
    }
}

class Caller {

    public void register(CallBack callback) {
        callback.methodToCallBack();
    }

    public static void main(String[] args) {
        Caller caller = new Caller();
        CallBack callBack = new CallBackImpl();       

//because of the interface, the type is Callback even 
//thought the new instance is the CallBackImpl class. 
//This alows to pass different types of classes that have 
//the implementation of CallBack interface

        caller.register(callBack);
    }
} 

在您的情况下,除了多线程之外,您还可以这样做:

interface ServerInterface {
    void newSeverConnection(Socket socket);
}

public class Server implements ServerInterface {

    public Server(int _address) {
        System.out.println("Starting Server...");
        serverConnectionHandler = new ServerConnections(_address, this);
        workers.execute(serverConnectionHandler);
        System.out.println("Do something else...");
    }

    void newServerConnection(Socket socket) {
        System.out.println("A function of my child class was called.");
    }

}

public class ServerConnections implements Runnable {

    private ServerInterface serverInterface;
    
    public ServerConnections(int _serverPort, ServerInterface _serverInterface) {
      serverPort = _serverPort;
      serverInterface = _serverInterface;
    }

    @Override
    public void run() {
        System.out.println("Starting Server Thread...");

        if (serverInterface == null) {
            System.out.println("Server Thread error: callback null");
        }

        try {
            mainSocket = new ServerSocket(serverPort);

            while (true) {
                serverInterface.newServerConnection(mainSocket.accept());
            }
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

多线程

请记住,这不处理多线程,这是另一个主题,可以根据项目有各种解决方案。

观察者模式

观察者模式几乎做到了这一点,主要区别在于使用 anArrayList添加多个侦听器。在不需要的地方,您可以通过一个参考获得更好的性能。

于 2013-08-16T18:05:36.327 回答
66

使用观察者模式。它是这样工作的:

interface MyListener{
    void somethingHappened();
}

public class MyForm implements MyListener{
    MyClass myClass;
    public MyForm(){
        this.myClass = new MyClass();
        myClass.addListener(this);
    }
    public void somethingHappened(){
       System.out.println("Called me!");
    }
}
public class MyClass{
    private List<MyListener> listeners = new ArrayList<MyListener>();

    public void addListener(MyListener listener) {
        listeners.add(listener);
    }
    void notifySomethingHappened(){
        for(MyListener listener : listeners){
            listener.somethingHappened();
        }
    }
}

您创建一个接口,当某些事件发生时,该接口具有一个或多个要调用的方法。然后,任何需要在事件发生时得到通知的类都实现了这个接口。

这允许更大的灵活性,因为生产者只知道侦听器接口,而不是侦听器接口的特定实现。

在我的例子中:

MyClass是这里的生产者,因为它通知了一个听众列表。

MyListener是界面。

MyForm对何时感兴趣somethingHappened,所以它正在实现MyListener并注册自己MyClass。现在可以在不直接引用的情况下MyClass通知事件。这是观察者模式的优势,它减少了依赖性并增加了可重用性。MyFormMyForm

于 2013-08-16T18:05:45.833 回答
7

IMO,你应该看看观察者模式,这就是大多数听众的工作方式

于 2013-08-16T17:52:53.320 回答
4

我不知道这是否是您正在寻找的,但您可以通过将回调传递给子类来实现这一点。

首先定义一个通用回调:

public interface ITypedCallback<T> {
    void execute(T type);
}

在 ServerConnections 实例化上创建一个新的 ITypedCallback 实例:

public Server(int _address) {
    serverConnectionHandler = new ServerConnections(new ITypedCallback<Socket>() {
        @Override
        public void execute(Socket socket) {
            // do something with your socket here
        }
    });
}

在回调对象上调用执行方法。

public class ServerConnections implements Runnable {

    private ITypedCallback<Socket> callback;

    public ServerConnections(ITypedCallback<Socket> _callback) {
        callback = _callback;
    }

    @Override
    public void run() {   
        try {
            mainSocket = new ServerSocket(serverPort);
            while (true) {
                callback.execute(mainSocket.accept());
            }
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

顺便说一句:我没有检查它是否100%正确,直接在这里编码。

于 2013-08-16T18:08:06.997 回答
1

在这种特殊情况下,以下应该有效:

serverConnectionHandler = new ServerConnections(_address) {
    public void newConnection(Socket _socket) {
        System.out.println("A function of my child class was called.");
    }
};

它是一个匿名子类。

于 2013-08-16T18:12:48.370 回答