Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find type without using instanceof?

I have a List of interface type Criteria within my class Query.

List<Criteria> criteria = new ArrayList<Criteria>();

I have several concrete implementations of Criteria. I want to give Query a method that iterates through my criteria list, and depending on the concrete type, execute some logic.

I'm presently doing this with instanceof like so:

for(Criteria c : criteria) {
    if(c instanceof ContextualCriteria){
        // logic
    }
    ...
}

Is this the only/best way?

like image 721
wulfgarpro Avatar asked Dec 09 '22 06:12

wulfgarpro


2 Answers

Does the logic sensibly belong in the Criteria itself? If so, put it into the Criteria interface and implement it appropriately for each concrete class implementing the Criteria interface. This is obviously the nice polymorphic approach.

Unfortunately, in real life OO doesn't always work as simply as that - sometimes it doesn't make sense to put the per-type behaviour in the type itself, so you may need to use instanceof instead. You could potentially have a map from "criteria class" to some interface representing the action to take, but that could easily end up being even messier.

Double-dispatch via the visitor pattern can sometimes improve things a little - so the logic could still be in separate methods in your "calling" class, but each Criteria can call back to the right method via a single interface method. Personally I tend to find this increases coupling and gets ugly quickly, but others swear by it.

like image 172
Jon Skeet Avatar answered Dec 27 '22 16:12

Jon Skeet


If the logic does not belong in the Criteria as Jon Skeet suggests, then you could use the visitor pattern.

In ConcreteCriteria:

public void accept(CriteriaVisitor v) {
    v.visit(this);
}

In the Client code:

public void method() {
    for (Criteria c : criteria) {
        c.accept(this);
    }
}

public void visit(ConcreteCriteria c) {
    // do logic here
}

public void visit(Criteria c) {
    // othervise...
}

This gets rid of the instanceof, but be wary, I have found that this pattern is difficult to understand if you are unfamiliar with the code.

like image 36
waxwing Avatar answered Dec 27 '22 17:12

waxwing