113

Having a chain of "instanceof" operations is considered a "code smell". The standard answer is "use polymorphism". How would I do it in this case?

There are a number of subclasses of a base class; none of them are under my control. An analogous situation would be with the Java classes Integer, Double, BigDecimal etc.

if (obj instanceof Integer) {NumberStuff.handle((Integer)obj);}
else if (obj instanceof BigDecimal) {BigDecimalStuff.handle((BigDecimal)obj);}
else if (obj instanceof Double) {DoubleStuff.handle((Double)obj);}

I do have control over NumberStuff and so on.

I don't want to use many lines of code where a few lines would do. (Sometimes I make a HashMap mapping Integer.class to an instance of IntegerStuff, BigDecimal.class to an instance of BigDecimalStuff etc. But today I want something simpler.)

I'd like something as simple as this:

public static handle(Integer num) { ... }
public static handle(BigDecimal num) { ... }

But Java just doesn't work that way.

I'd like to use static methods when formatting. The things I'm formatting are composite, where a Thing1 can contain an array Thing2s and a Thing2 can contain an array of Thing1s. I had a problem when I implemented my formatters like this:

class Thing1Formatter {
  private static Thing2Formatter thing2Formatter = new Thing2Formatter();
  public format(Thing thing) {
      thing2Formatter.format(thing.innerThing2);
  }
}
class Thing2Formatter {
  private static Thing1Formatter thing1Formatter = new Thing1Formatter();
  public format(Thing2 thing) {
      thing1Formatter.format(thing.innerThing1);
  }
}

Yes, I know the HashMap and a bit more code can fix that too. But the "instanceof" seems so readable and maintainable by comparison. Is there anything simple but not smelly?

Note added 5/10/2010:

It turns out that new subclasses will probably be added in the future, and my existing code will have to handle them gracefully. The HashMap on Class won't work in that case because the Class won't be found. A chain of if statements, starting with the most specific and ending with the most general, is probably the best after all:

if (obj instanceof SubClass1) {
    // Handle all the methods and properties of SubClass1
} else if (obj instanceof SubClass2) {
    // Handle all the methods and properties of SubClass2
} else if (obj instanceof Interface3) {
    // Unknown class but it implements Interface3
    // so handle those methods and properties
} else if (obj instanceof Interface4) {
    // likewise.  May want to also handle case of
    // object that implements both interfaces.
} else {
    // New (unknown) subclass; do what I can with the base class
}
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
Mark Lutton
  • 6,959
  • 7
  • 41
  • 57
  • 4
    I'd suggest a [visitor pattern][1]. [1]: http://en.wikipedia.org/wiki/Visitor_pattern – lexicore May 07 '10 at 16:45
  • Is it the ifthen chain you object to, or simply the use of "instanceof"? – G__ May 07 '10 at 16:52
  • 31
    The Visitor pattern requires adding a method to the target class (Integer for instance) -- easy in JavaScript, hard in Java. Excellent pattern when designing the target classes; not so easy when trying to teach an old Class new tricks. – Mark Lutton May 07 '10 at 17:08
  • 5
    @lexicore: markdown in comments is limited. Use `[text](link)` to post links in comments. – BalusC May 07 '10 at 18:28
  • 2
    "But Java just doesn't work that way." Maybe I'm misunderstanding things, but Java supports method overloading (even on static methods) just fine... it's just that your methods above are missing the return type. – Powerlord May 10 '10 at 15:05
  • 1
    Here's what Java doesn't allow: public static void handle(Integer i) {...} public static void handle (Double d) { ... } public static void main (String[] args) { Number n = new Integer(1); handle(n); }. – Mark Lutton May 11 '10 at 15:26
  • @MarkLutton Then create a wrapper and add it to that. – Christopher Perry Feb 16 '13 at 01:08
  • 4
    @Powerlord Overload resolution is *static* at *compile-time*. – Aleksandr Dubinsky Jan 22 '15 at 16:18
  • Any solution in 2022?? – Long Jun 05 '22 at 03:38

10 Answers10

60

You might be interested in this entry from Steve Yegge's Amazon blog: "when polymorphism fails". Essentially he's addressing cases like this, when polymorphism causes more trouble than it solves.

The issue is that to use polymorphism you have to make the logic of "handle" part of each 'switching' class - i.e. Integer etc. in this case. Clearly this is not practical. Sometimes it isn't even logically the right place to put the code. He recommends the 'instanceof' approach as being the lesser of several evils.

As with all cases where you are forced to write smelly code, keep it buttoned up in one method (or at most one class) so that the smell doesn't leak out.

DJClayworth
  • 26,349
  • 9
  • 53
  • 79
  • 23
    Polymorphism does not fail. Rather, Steve Yegge fails to invent the Visitor pattern, which is the perfect replacement for `instanceof`. – Rotsor May 28 '11 at 07:57
  • 13
    I don't see how visitor helps here. The point is that the response of OpinionatedElf to NewMonster shouldn't be encoded in NewMonster, but in OpinionatedElf. – DJClayworth Jun 07 '11 at 18:22
  • 1
    If `Monster` is made visitable, the elf can visit it to extract all the information it needs, thus keeping the logic in the `OpinionatedElf` class without resorting to the dangerous practices of using reflection. – Rotsor Jun 07 '11 at 18:32
  • You miss the point. If OpinionatedElf could use the public interface of each Monster to make it's decision there wouldn't be an issue in the first place. – DJClayworth Jun 08 '11 at 20:30
  • And why `OpinionatedElf` can't use the public interface of each `Monster`? It has to depend on it to do `instanceof` anyway. I totally miss it now. – Rotsor Jun 09 '11 at 09:36
  • 2
    The point of the example is that OpinionatedElf cannot tell from available data whether it likes or dislikes the Monster. It has to know what Class the Monster belongs to. That requires either an instanceof, or the Monster has to know in some way whether the OpinionatedElf likes it. Visitor doesn't get round that. – DJClayworth Jun 09 '11 at 13:33
  • 2
    @DJClayworth Visitor pattern *does* get around that by adding a method to `Monster` class, responsibility of which is basically to introduce the object, like "Hello, I am an Orc. What do you think about me?". Opinionated elf can then judge monsters based on these "greetings", with a code similar to `bool visitOrc(Orc orc) { return orc.stench() T accept(MonsterVisitor v) { v.visitOrc(this); } }`, enough for every monster inspection once and for all. – Rotsor Jun 09 '11 at 13:57
  • This is not the place for this discussion. Contact me by chat and I will explain why your solution doesn't work. – DJClayworth Jun 09 '11 at 14:17
  • 2
    See @Chris Knight 's answer for the reason why Visitor can not be applied in some cases. – James P. Mar 26 '12 at 13:02
  • 1
    @Rotsor It doesn't solve anything if the decision has to be made only upon the type of the object that is accepting the visitor. The thing here is that types also carry an information upon which a decision can be made and adding additional information for the same decision is redundant and can lead to needless memory overhead. – luke1985 Mar 02 '14 at 13:19
  • 1
    I've been looking for this answer and found several on SO where the visitor pattern is suggested. Missing the point of the question! It seems the visitor pattern is greatly misunderstood. – Ben Thurley Jan 28 '15 at 13:00
  • 1
    @Rotsor The point of question that you can't change class that should be visited, and you can't add `accept visitor` method – B-GangsteR Oct 03 '17 at 06:35
20

As highlighted in the comments, the visitor pattern would be a good choice. But without direct control over the target/acceptor/visitee you can't implement that pattern. Here's one way the visitor pattern could possibly still be used here even though you have no direct control over the subclasses by using wrappers (taking Integer as an example):

public class IntegerWrapper {
    private Integer integer;
    public IntegerWrapper(Integer anInteger){
        integer = anInteger;
    }
    //Access the integer directly such as
    public Integer getInteger() { return integer; }
    //or method passthrough...
    public int intValue() { return integer.intValue(); }
    //then implement your visitor:
    public void accept(NumericVisitor visitor) {
        visitor.visit(this);
    }
}

Of course, wrapping a final class might be considered a smell of its own but maybe it's a good fit with your subclasses. Personally, I don't think instanceof is that bad a smell here, especially if it is confined to one method and I would happily use it (probably over my own suggestion above). As you say, its quite readable, typesafe and maintainable. As always, keep it simple.

joragupra
  • 692
  • 1
  • 12
  • 23
Chris Knight
  • 24,333
  • 24
  • 88
  • 134
  • Yes, "Formatter", "Composite", "Different types" all seams to point in the direction of visitor. – Thomas Ahle Jan 03 '12 at 11:37
  • 4
    how do you determine which wrapper you are going to use? through a if instanceof branching? – fast tooth Dec 19 '15 at 00:04
  • 3
    As @fasttooth points out this solution only shifts the problem. Instead of using `instanceof` to call the right `handle()` method you'll now have to use it the call the right `XWrapper` constructor... – Matthias Jan 25 '17 at 17:10
18

Instead of a huge if, you can put the instances you handle in a map (key: class, value: handler).

If the lookup by key returns null, call a special handler method which tries to find a matching handler (for example by calling isInstance() on every key in the map).

When a handler is found, register it under the new key.

This makes the general case fast and simple and allows you to handle inheritance.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • +1 I have used this approach when handling code generated from XML schemas, or messaging system, where there are dozens of object types, handed to my code in an essentially non-typesafe way. – DNA Oct 18 '12 at 19:46
16

You can use reflection:

public final class Handler {
  public static void handle(Object o) {
    try {
      Method handler = Handler.class.getMethod("handle", o.getClass());
      handler.invoke(null, o);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  public static void handle(Integer num) { /* ... */ }
  public static void handle(BigDecimal num) { /* ... */ }
  // to handle new types, just add more handle methods...
}

You can expand on the idea to generically handle subclasses and classes that implement certain interfaces.

Jordão
  • 55,340
  • 13
  • 112
  • 144
  • 41
    I would argue that this smells even more then the instanceof operator. Should work though. – Tim Büthe Feb 21 '11 at 17:29
  • 6
    @Tim Büthe: At least you don't have to deal with a growing `if then else` chain in order to add, remove or modify handlers. The code is less fragile to changes. So I'd say that for this reason it's superior to the `instanceof` approach. Anyway, I just wanted to give a valid alternative. – Jordão Feb 21 '11 at 17:55
  • 1
    This is essentially how a dynamic language would handle the situation, via [duck typing](http://en.wikipedia.org/wiki/Duck_typing) – DNA Oct 18 '12 at 19:44
  • @DNA: wouldn't that be [multimethods](http://en.wikipedia.org/wiki/Multimethods)? – Jordão Oct 18 '12 at 23:10
  • @Jordão Oops, yes! I shouldn't post so late at night ;-) – DNA Oct 19 '12 at 21:41
  • 1
    Why do you iterate over all methods instead of using `getMethod(String name, Class>... parameterTypes)`? Or else I would replace `==` with `isAssignableFrom` for the parameter's type check. – Aleksandr Dubinsky Jan 22 '15 at 16:24
  • @AleksandrDubinsky: you're right, it would be better to call it directly like that. I'll check later and change it accordingly. – Jordão Jan 22 '15 at 21:07
  • Adding reflection to production code can cause drastic results as Reflection is comparatively lot slower depending upon the operation. Please read: http://stackoverflow.com/a/435568/988206 – Dipesh Gupta Aug 03 '15 at 06:47
  • 1
    @DipeshGupta: you're absolutely right, I think that should go without saying. – Jordão Aug 03 '15 at 12:50
10

I think that the best solution is HashMap with Class as key and Handler as value. Note that HashMap based solution runs in constant algorithmic complexity θ(1), while the smelling chain of if-instanceof-else runs in linear algorithmic complexity O(N), where N is the number of links in the if-instanceof-else chain (i.e. the number of different classes to be handled). So the performance of HashMap based solution is asymptotically higher N times than the performance of if-instanceof-else chain solution. Consider that you need to handle different descendants of Message class differently: Message1, Message2, etc. . Below is the code snippet for HashMap based handling.

public class YourClass {
    private class Handler {
        public void go(Message message) {
            // the default implementation just notifies that it doesn't handle the message
            System.out.println(
                "Possibly due to a typo, empty handler is set to handle message of type %s : %s",
                message.getClass().toString(), message.toString());
        }
    }
    private Map<Class<? extends Message>, Handler> messageHandling = 
        new HashMap<Class<? extends Message>, Handler>();

    // Constructor of your class is a place to initialize the message handling mechanism    
    public YourClass() {
        messageHandling.put(Message1.class, new Handler() { public void go(Message message) {
            //TODO: IMPLEMENT HERE SOMETHING APPROPRIATE FOR Message1
        } });
        messageHandling.put(Message2.class, new Handler() { public void go(Message message) {
            //TODO: IMPLEMENT HERE SOMETHING APPROPRIATE FOR Message2
        } });
        // etc. for Message3, etc.
    }

    // The method in which you receive a variable of base class Message, but you need to
    //   handle it in accordance to of what derived type that instance is
    public handleMessage(Message message) {
        Handler handler = messageHandling.get(message.getClass());
        if (handler == null) {
            System.out.println(
                "Don't know how to handle message of type %s : %s",
                message.getClass().toString(), message.toString());
        } else {
            handler.go(message);
        }
    }
}

More info on usage of variables of type Class in Java: http://docs.oracle.com/javase/tutorial/reflect/class/classNew.html

Serge Rogatch
  • 13,865
  • 7
  • 86
  • 158
  • 3
    for a small number of cases (probably higher than the number of those classes for any real example) the if-else would outperform the map, besides of no using heap memory at all – idelvall Aug 27 '18 at 19:27
9

You could consider the Chain of Responsibility pattern. For your first example, something like:

public abstract class StuffHandler {
   private StuffHandler next;

   public final boolean handle(Object o) {
      boolean handled = doHandle(o);
      if (handled) { return true; }
      else if (next == null) { return false; }
      else { return next.handle(o); }
   }

   public void setNext(StuffHandler next) { this.next = next; }

   protected abstract boolean doHandle(Object o);
}

public class IntegerHandler extends StuffHandler {
   @Override
   protected boolean doHandle(Object o) {
      if (!o instanceof Integer) {
         return false;
      }
      NumberHandler.handle((Integer) o);
      return true;
   }
}

and then similarly for your other handlers. Then it's a case of stringing together the StuffHandlers in order (most specific to least specific, with a final 'fallback' handler), and your despatcher code is just firstHandler.handle(o);.

(An alternative is to, rather than using a chain, just have a List<StuffHandler> in your dispatcher class, and have it loop through the list until handle() returns true).

Cowan
  • 37,227
  • 11
  • 66
  • 65
7

Just go with the instanceof. All the workarounds seem more complicated. Here is a blog post that talks about it: http://www.velocityreviews.com/forums/t302491-instanceof-not-always-bad-the-instanceof-myth.html

Jose Martinez
  • 11,452
  • 7
  • 53
  • 68
0

I have solved this problem using reflection (around 15 years back in pre Generics era).

GenericClass object = (GenericClass) Class.forName(specificClassName).newInstance();

I have defined one Generic Class ( abstract Base class). I have defined many concrete implementations of base class. Each concrete class will be loaded with className as parameter. This class name is defined as part of configuration.

Base class defines common state across all concrete classes and concrete classes will modify the state by overriding abstract rules defined in base class.

At that time, I don't know the name of this mechanism, which has been known as reflection.

Few more alternatives are listed in this article : Map and enum apart from reflection.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
0

Add a method in BaseClass which returns name of the class. And override the methods with the specific class name

public class BaseClass{
  // properties and methods
  public String classType(){
      return BaseClass.class.getSimpleName();
  }
}

public class SubClass1 extends BaseClass{
 // properties and methods
  @Override
  public String classType(){
      return SubClass1.class.getSimpleName();
  }
}

public class SubClass2 extends BaseClass{
 // properties and methods
  @Override
  public String classType(){
      return SubClass1.class.getSimpleName();
  }
}

Now use the switch case in following way-

switch(obj.classType()){
    case SubClass1:
        // do subclass1 task
        break;
    case SubClass2:
        // do subclass2 task
        break;
}
Shahriar Miraj
  • 307
  • 3
  • 14
-1

What I use for Java 8:

void checkClass(Object object) {
    if (object.getClass().toString().equals("class MyClass")) {
    //your logic
    }
}
Sijan Bhandari
  • 29
  • 1
  • 1
  • 9