0

I want to avoid the using of instanceof:

here is my case :

The definition of my Events classes are in a commons module :

public class Event1 extends AbstractEvent{

}

public class Event2 extends AbstractEvent{

}

public class Event3 extends AbstractEvent{

}

in another module called jms i have a listener that receive Event message from a queue :

public class MyMessageListener implements MessageListener {

@Override
public void onMessage(Message message) {
// CONVERT message to Event Object 
    if (event instanceof Event1) {
    // Execute Processing 1
    }

    if (event instanceof Event2) {
    // Execute Processing 2
    }

    if (event instanceof Event3) {
    // Execute Processing 3
    }

}

I want to avoid using instanceof and the best things for doing this is the visitor pattern with an execute method in the AbstractEvent and every leaf classes will implement it .

My problem is that in the common package i don't have access to the classes responsible for the processing . theses classes exist only in the jms module .

Is there any Tips or hint to do this (Advanced Visitor) or another pattern to do that

1
  • I would add abstract method to AbstractEvent and move processing code to events Commented Nov 26, 2014 at 12:16

4 Answers 4

2

Put all possible behaviours to Map<Class, Runnable> and match event's type and Runnable type.

Sign up to request clarification or add additional context in comments.

2 Comments

Note that for this to work, the Event classes need to be final, or you risk subclasses not being recognized as their parent (or vice-versa).
@Darkhogg depends on matching algorithm. you can use instanceof, class equality or whatever else.
1

In such cases, the visitor Pattern can sometimes help. The visitor pattern is mainly suitable if your class hierarchy doesn't change much, because for each change in the class hierarchy you also must change the visitor (but that is also the case if you're using `instanceof').

To use the visitor pattern, you need to define a Visitor interface which contains a visit method for all types you want to visit:

interface Visitor { 
    visit(Event1 event);
    visit(Event2 event);
    visit(Event3 event);
}

first you want a common superclass which is the root for all classes you want to apply the visitor to. This superclass contains a method callVisitor:

public abstract class MyEvent extends AbstractEvent {
    public abstract void visit(Visitor v);
}

public class Event1 extends MyEvent{
    public void visit(Visitor v) {
        v.visit(this); // calls visit(Event1)
    }
}

public class Event2 extends MyEvent{
    public void visit(Visitor v) {
        v.visit(this); // calls visit(Event2)
    }
}

public class Event3 extends MyEvent{
    public void visit(Visitor v) {
        v.visit(this); // calls visit(Event3)
    }
}

Finally, you can create a visitor instance every time you need different behaviour based on the runtime type of the class:

public void onMessage(Message message) {
    Visitor v = new Visitor() {
        public void visit(Event1 event) {
            // Execute Processing 1
        }
        public void visit(Event2 event) {
            // Execute Processing 2
        }
        public void visit(Event3 event) {
            // Execute Processing 3
        }
    }
    event.visit(v);
}

The visitor pattern might be overkill in your situation, but I find it useful sometimes. The major advantage over using instanceof and other possible solutions is that it is typesafe: if you add a class to the hierarchy, the project will not compile until you added a visitor method to all visitors you defined.

Comments

1

As an alternative approach to the other answers, you could move the decision logic into your messaging configuration, so that each type of event is consumed by a MessageListener dedicated to processing only one type of Event. This will remove any "if" logic from your Consumer.

A caveat to this approach is that multiple consumers may process the events out of order. If this is an issue for your problem domain you may not wish to deal with the out-of-sequence issues yourself.

See JMS Selectors for more information

The advantages to this approach are:

  • Consumers are responsible for only one Event type (simplification)
  • You can add more Consumers independently based on event type (scalability)

Comments

0

You could have the AbstractEvent declare an abstract isOfType() method:

public abstract class AbstractEvent {
    public abstract boolean isOfType( String type );
}

It would eliminate the instanceof's but not the if switching, though...

Cheers,

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.