views:

142

answers:

3

I have this situation:

interface MessageListener
{
   void onMessageReceipt(Message message);
}

class MessageReceiver
{
  MessageListener listener;
  public MessageReceiver(MessageListener listener, other arguments...)
  {
     this.listener = listener;
  }

  loop()
  {
    Message message = nextMessage();
    listener.onMessageReceipt(message);
  }
}

and I want to avoid the following pattern: (Using the this in the Client constructor)

class Client implements MessageListener
{
   MessageReceiver receiver;
   MessageSender sender;

  public Client(...)
  {
    receiver = new MessageReceiver(this, other arguments...);
    sender = new Sender(...);
  }
  .
  .
  .
  @Override
  public void onMessageReceipt(Message message)
  {
     if(Message.isGood())
       sender.send("Congrtulations");
     else
       sender.send("Boooooooo");
  }
}

The reason why i need the above functionality is because i want to call the sender inside the onMessageReceipt() function, for example to send a reply. But I dont want to pass the sender into a listener, so the only way I can think of is containing the sender in a class that implements the listener, hence the above resulting Client implementation. Is there a way to achive this without the use of 'this' in the constructor? It feels bizare and i dont like it, since i am passing myself to an object(MessageReceiver) before I am fully constructed. On the other hand, the MessageReceiver is not passed from outside, it is constructed inside, but does this 'purifies' the bizarre pattern? I am seeking for an alternative or an assurance of some kind that this is safe, or situations on which it might backfire on me.

+6  A: 

The Client's dependencies (such as MessageReceiver) could be injected into it rather than having the Client know how to construct the MessageReceiver:

Client client = new Client(...);
MessageReceiver rcvr = new MessageReceiver(client, ...);
client.setMessageReceiver(rcvr);

However I would suggest looking into breaking the circular dependency between these two classes, it sounds as if something is off in your design.

The real reason why passing this to another class in the first class's constructor is a bad practice is because you are allowing a reference to this to escape before it is fully constructed.

matt b
Hmmm... Maybe do what you suggest in a static factory method for creating a Client. Nice. I ll try it.As far as the circular dep, it is intuitive because Client uses(contains) the receiver to get messages and also IS a listener since it processes the messages, thus becoming a listener.
Paralife
Perhaps it is a naming thing but "receiver" and "listener" sound like synonyms here to me
matt b
You are right. Listener could be named Handler or Processor. It would be more clear then.
Paralife
+2  A: 

It wont backfire on you as long as this is never referenced before construction. However, you should never rely on that assumption. Concurrency is a big factor here, as well as the contract for the code you pass it to.

Since Client is a MessageReceiver, why not make it one?

public Client extends MessageReceiver implements MessageListener{
    /* ... */
}
Jeremy
This was my first implementation but i will need to decouple how the Client 'handles' the messages(this is application logic) from how the client 'receives' them(this could be JMS, Rabbit, or totally other way).
Paralife
+1  A: 

I don't see where the MessageReceiver is used, so at the moment you could write the code without MessageReceiver like this and it would be effectively the same:

interface MessageListener
{
    void onMessageReceipt(Message message);
}

class Client implements MessageListener
{
    MessageSender sender;

    public Client(...)
    {
        sender = new Sender(...);
    }
    .
    .
    .
    @Override
    public void onMessageReceipt(Message message)
    {
        if(Message.isGood())
            sender.send("Congrtulations");
        else
            sender.send("Boooooooo");
    }
}

I think a standard publish-subscribe or Observer pattern is probably what you need - but it's hard to tell without understanding the subtleties of the problem that you are trying to solve.

richj
MessageReceiver calls the onMessageReceipt() method of a MessageListener that you pass to the MessageReceiver. So in your solution i must pass the Client to the MessageReceiver since my client is a listener too, which is effectively what I already do.
Paralife
MessageReceiver.loop() calls the MessageListener.onMessageReceipt() method, but it isn't clear how the loop() method is called. The MessageReceiver isn't visible from outside of Client - at least not in any of the code shown so far.
richj
the loop is called externally when want to start/resume receiving messages
Paralife
So MessageReceiver is visible outside of Client?
richj
No. client starts the receiver loop. The conditions that trigger the client to start the receiver loop can be external, e.g. a public method of the client, that in its implementation starts the receiver's loop.
Paralife