Question

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?

Was it helpful?

Solution 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.

OTHER TIPS

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>() {
        ...
    };
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top