Java – Resolving circular dependency between two classes

circular-dependencydependency-managementjava

I am trying to resolve a circular dependency between two components in my system. The Messenger component is responsible for sending and receiving messages on a web socket. The Controller component requires use of the Messenger component to be able to send messages to connected clients because the Messenger component knows about the connected sessions.

The Messenger component has a dependency on the Controller component to be able notify the controller of incoming messages.

The WebsocketHandler is a framework interface that I have no control over in this case and calls the appropriate methods on my implementation based on the connected clients.

What architectural changes could I make to resolve this?

UML Diagram

interface WebsocketHandler
{
    void onConnect(Session session);
    void onDisconnect(Session session);
    void recieve(Object payload);
}

class Messenger implements WebsocketHandler
{
    Controller controller;
    Set<WebsocketSession> websocketSessions;

    @Override
    void onConnect(Session session)
    {
        sessions.add(session);
    }

    @Override
    void onDisconnect(Session session)
    {
        sessions.remove(session);
    }

    @Override
    void recieve(Object payload)
    {
        controller.messageReceived(payload);
    }

    // requires access to sessions to send messages
    void send(Object payload)
    {
        for (WebsocketSession session : websocketSessions)
        {
            session.send(payload);
        }
    }
}

class Controller
{
    Messenger messenger;

    void messageReceived(Object payload)
    {
        // do something with payload
    }

    void notifyClients()
    {
        messenger.send(...);
    }
}

Best Answer

The simple solution to this is to recognise that Controller doesn't need a dependency on Messenger, it needs a dependency on send. So provide it with that dependency:

interface Sender {
    void send(Object payload);
}

class Messenger implements WebsocketHandler, Sender { …

class Controller
{
    Sender sender;

    void messageReceived(Object payload)
    {
        // do something with payload
    }

    void notifyClients()
    {
        sender.send(...);
    }
}

Now, Controller just has a dependency on the Sender interface, removing that circular dependency.

UPDATE

As the OP points out, the above removes the direct circular dependency between Controller and Messenger. However, if constructor injection is used, the dependency still exists at the point of creation of the objects: we need to create Sender first to satisfy Controller's need for a Sender, but we need to create Controller first as Messenger needs to call controller.messageReceived(payload).

There are various ways of working around this, such as supporting property injection. But my personally favourite, for languages that support functions as first class citizens is to fully decouple the two objects via functions.

Such a solution, expressed as C# (as I'm more familiar with that language), might look like:

class Messenger : WebsocketHandler
{
    private readonly Action<object> _messageReceived;
    private readonly IEnumerable<WebsocketSession> _websocketSessions;

    public Messenger(Action<object> messageReceived) 
        => _messageReceived = messageReceived;


    public void Receive(object payload) => _messageReceived(payload);

    public void Send(Object payload)
    {
        foreach (var session in _websocketSessions)
        {
            session.Send(payload);
        }
    }
}

class Controller
{
    private readonly Action<object> _send;

    public Controller(Action<object> send) => _send = send;

    public void MessageReceived(object payload)
    {
        // do something with payload
    }

    public void NotifyClients() => _send(null);
}

And then the code to couple the two objects at runtime might be something like:

void Setup()
{
    Controller controller = null;
    var messenger = new Messenger(MessageReceiver);
    controller = new Controller(Sender);

    void MessageReceiver(object payload) => controller.MessageReceived(payload);
    void Sender(object payload) => messenger.Send(payload);
}

Java these days supports such an approach too. I do not know though how well this would work with IoC frameworks like Spring.