Подтвердить что ты не робот

Как выполнить обратный вызов JAVA между классами?

Я исхожу из 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.");
};

в классе родителя, что явно неверно?

4b9b3361

Ответ 1

Определите интерфейс и реализуйте его в классе, который получит обратный вызов.

Обратите внимание на многопоточность в вашем случае.

Пример кода из http://cleancodedevelopment-qualityseal.blogspot.com.br/2012/10/understanding-callbacks-with-java.html

interface CallBack {
    void methodToCallBack();
}

class CallBackImpl implements CallBack {
    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();
        caller.register(callBack);
    }
} 

Ответ 2

Используйте шаблон наблюдателя. Он работает следующим образом:

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 может сообщить MyForm о событиях без прямого ссылки на MyForm. Это сила шаблона наблюдателя, он уменьшает зависимость и увеличивает повторное использование.

Ответ 3

IMO, вы должны взглянуть на шаблон наблюдателя, и именно так работают большинство слушателей.

Ответ 4

Я не знаю, это то, что вы ищете, но вы можете добиться этого, передав обратный вызов дочернему классу.

сначала определите общий обратный вызов:

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

создать новый экземпляр ITypedCallback в экземпляре ServerConnections:

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

btw: я не проверял, правильно ли он на 100%, прямо закодировал его здесь.

Ответ 5

В этом конкретном случае должно работать следующее:

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

Это анонимный подкласс.