Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conflict between separating logic and polymorphism

I'm trying to create a messaging system in Java. I have an interface Message which will have multiple implementations (e.g. TextMessage and AudioMessage). This interface will be available on both the server and the client.

My problem is that the client should render different visual output based on the type of message it receives from the server. Therefore I either have to know the type of the message I'm dealing with which I could do using instanceof() or I can put an abstract method in the Message interface and make use of polymorphism so the Message takes care of creating the visual output.

However doing any of that feels dirty as I'd have to either create a new if instanceof block every time or let the Message take care of creating the visual part, which feels just as wrong, as it is supposed to be some kind of model.

Does anyone have a solution or an appropriate design pattern I could use here?

Thanks!

like image 930
reveance Avatar asked Jan 21 '14 14:01

reveance


2 Answers

You can use Visitor Pattern for this.

interface Message{
     public void accept(MessageVisitor visitor);
}

interface MessageVisitor{
    public void visit(TextMessage message);
    public void visit(AudioMessage message);
}

class PrintVisitor implements MessageVisitor{
    public void visit(TextMessage message){
         //print text message
    }

    public void visit(AudioMessage message){
        //do step required
    }
}

class TextMessage implements Message{
     //other methods

     public void accept(MessageVisitor visitor){
          visitor.visit(this);
     }
}

Using this double dispatch technique your instanceof checks are not required. As well as the Printing logic goes out in the PrintVisitor class, which allows for greater flexibility.

visitor.visit(this); in this line you are calling visit on visitor with this, now this will use the actual type of instance, so the method of visitor that will be called will be according to actual type.

How do you achieve flexibility?

Because now you can add new operations to your Message class without changing the actual code of Message using Visitors

Beware of some downfalls too. When your hierarchy of Message changes it will cause change in all the Visitors. So do take care of that.

like image 168
Narendra Pathai Avatar answered Nov 03 '22 23:11

Narendra Pathai


In Java, you should be looking at creating a Visitor type of pattern:

public interface MsgVisitor{
  public Command handleMsg(FooMsg msg);
  public Command handleMsg(BarMsg msg);
  public Command handleMsg(BazMsg msg);
}

abstract class MyMessage{
  public Command visit(MsgVisitor visitor){
    return visitor.handleMsg(this);
  }
}

and then you send what comes out of it down the pipeline so that the correct Command is tied to the correct message type.

The Command (using the Command pattern) is what ties in what you need to do with the message and what it means. Therefore, this visitor just is there to assemble Commands. It acts as a delegation point for actions. This allows you a richer way of handling and assembling hierarchy of logic.

like image 2
wheaties Avatar answered Nov 03 '22 23:11

wheaties