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

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.

  • This sounds great but what about the fact Sender needs access to the session held in Messenger. Would it make sense to extract them into some sort of session registry component? – Robert Hunt Aug 9 at 19:10
  • @RobertHunt Which one? – Goyo Aug 9 at 20:23
  • @Goyo the Messenger class currently stores a set of websocket sessions as clients connect and disconnect, for the Sender to send a message it needs access to these sessions. – Robert Hunt Aug 9 at 21:35
  • 1
    Yes, but knowledge of that session is not part of the Sender interface. Breaking Sender Method signatuure breaks the circular dependency between Messenger and Controller and abstracts away implementation details of sendini a message.Session is an implementation detail that happega to be necessart for Messenger that implementation the Sender. At some future point in time you might replace implementation of Sender with one that sends its messages to Kafka topic for example and Controller will not care a one bit. – Roland Tepp Aug 10 at 5:17
  • 1
    @DavidArno Sorry, I had missed the fact you had Messenger implementing the Sender interface, it makes sense now. – Robert Hunt Aug 10 at 6:50

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

OMG java does not have events!!!

It does have several alternatives though. For example

https://docs.oracle.com/javase/6/docs/api/java/util/Observable.html

Here you would make your Messenger implement Observable and have the Controller call addObserver The Messenger can then notify the Controller of incoming messages with its notifyObservers() function without having to reference the Controller class.

There are several variations on the technique.

https://docs.oracle.com/javase/tutorial/uiswing/events/index.html

The Idea is that you pass in to the messenger the function to call when a message comes in rather than passing in the whole controller class.

  • This is a classic example of "when you have a circular dependency, often there is a third object wanting to come out". In this case, the object is the observer (which turns out to be the same object, but seen through a different protocol). – Jörg W Mittag Aug 9 at 15:52

In that particular case (when you need to notify someone about something), you can use an aggregator\messenger.

One of my favorite (from C# though) is this one: https://github.com/NimaAra/Easy.MessageHub

You create a message class, you subscribe your service, you fire the message from another service - that's it. Behind the scenes, aggregator just defines the list of subscribers, who should be notified for the particular message.

I'm pretty sure Java should have something similar.

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.