문제

So I tried to make a subscription model with generics.. it looked nice, but now I'm running into some issues.

Receiver

public interface Receiver<E> {
    public void receive(E event);
}

Subscription registry

public class ClientRegistry<T> {
    private Set<Receiver<T>> clients = new HashSet<Receiver<T>>();

    public void subscribe(Receiver<T> client) {
        clients.add(client);
    }

    public void unsubscribe(Receiver<T> client) {
        clients.remove(client);
    }

    public void broadcast(T eventObject) {
        for(Receiver<T> client: clients) {
            client.receive(eventObject);
        }       
    }   
}

Sounds good so far, eh?

Now the problems come:

public class Screen implements Receiver<KeyEvent>, Receiver<MouseMoveEvent> {
    @Override
    public void receive(KeyEvent event)
    {
        // work
    }

    @Override
    public void receive(MouseMoveEvent event)
    {
        // work
    }
}

Now this is invalid syntax:

The interface Receiver cannot be implemented more than once
with different arguments: Receiver<MouseMoveEvent> and Receiver<KeyEvent>

How can I alter my system to keep it as generic as possible, but make it work?

도움이 되었습니까?

해결책 2

I would reverse the order, and use a Visitor Pattern:

import java.util.*;

interface Event{
    void receive(Receiver receiver);    
}

class KeyEvent implements Event{
    @Override
    public void receive(Receiver receiver){
        receiver.receive(this);
    }   
}

class MouseEvent implements Event {
    @Override
    public void receive(Receiver receiver){
        receiver.receive(this);
    }   
}

interface Receiver {
    void receive(KeyEvent event);
    void receive(MouseEvent event);
}

class ClientRegistry {
    private Set<Receiver> clients = new HashSet<Receiver>();

    public void subscribe(Receiver client) {
        clients.add(client);
    }

    public void unsubscribe(Receiver client) {
        clients.remove(client);
    }

    public void broadcast(Event eventObject) {
        for(Receiver client: clients) {
            eventObject.receive(client);
        }       
    }   
}

public class Screen implements Receiver {

    public void receive(KeyEvent event) {
        //work
        System.out.println("Processing key event");
    }
    public void receive(MouseEvent event) {
        //work
        System.out.println("Processing mouse event");
    }


    public static void main(String[] args){
        ClientRegistry registry = new ClientRegistry();
        registry.subscribe(new Screen());
        registry.broadcast(new MouseEvent());
    }
}

There is not way to generify the Receiver interface, but it is indeed type safe and as you can see, I reverse the order, since now it is the event the one which chooses the receiver and not otherwise.

다른 팁

Don't make the Screen class itself implement the two Receiver interfaces. Instead, use composition:

public class Screen {
    private Receiver<KeyEvent> keyReceiver = new Receiver<KeyEvent>() {
        ...
    };

    private Receiver<MouseEvent> mouseReceiver = new Receiver<MouseEvent>() {
        ...
    };
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top