如何在类之间执行JAVA回调?

时间:2013-08-16 17:49:42

标签: java callback

我来自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类中,显然不正确?

5 个答案:

答案 0 :(得分:108)

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

注意你的情况下的多线程。

来自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);
        }
    }
}

多线程

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

观察者模式

观察者模式几乎就是这样,主要区别在于使用ArrayList来添加多个侦听器。如果不需要,可以通过一个参考获得更好的性能。

答案 1 :(得分:56)

使用观察者模式。它的工作原理如下:

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是界面。

MyFormsomethingHappened时间感兴趣,因此它正在实施MyListener并向MyClass注册。现在MyClass可以在不直接引用MyForm的情况下通知MyForm有关事件的信息。这是观察者模式的优势,它降低了依赖性并提高了可重用性。

答案 2 :(得分:6)

IMO,你应该看一下Observer Pattern,这就是大多数听众的工作方式

答案 3 :(得分:3)

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

首先定义一个通用回调:

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

在回调对象上调用execute方法。

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%正确,在此处直接编码。

答案 4 :(得分:0)

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

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

这是一个匿名的子类。