Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why not use instanceof operator in OOP design?

Tags:

oop

instanceof

It has been repeatedly said that the instanceof operator should not be used except in the equals() method, otherwise it's a bad OOP design.

Some wrote that this is a heavy operation, but it seems that, at least java, handles it pretty well (even more efficiently than Object.toString() comparison).

Can someone please explain, or direct me to some article which explains why is it a bad design?

Consider this:

Class Man{
  doThingsWithAnimals(List<Animal> animals){
    for(Animal animal : animals){
      if(animal instanceOf Fish){
        eatIt(animal);
      }
      else if(animal instanceof Dog){
        playWithIt(animal);
      }
    }
  }
  ...
}

The decision of what to do with the Animal, is up to the Man. Man's desires can also change occasionally, deciding to eat the Dog, and play with the Fish, while the Animals don't change.

If you think the instanceof operator is not the correct OOP design here, please tell how would you do it without the instanceof, and why?

like image 432
user1028741 Avatar asked Dec 14 '13 23:12

user1028741


People also ask

Why you should not use Instanceof?

The instanceof operator can be used to call a method based explicitly on the class of some object, instead of implicitly using an overridden method and polymorphism. Thus, inexperienced programmers may mistakenly use instanceof where an overidden method is more appropriate.

Why do we need Instanceof operator?

The instanceof operator in Java is used to check whether an object is an instance of a particular class or not. objectName instanceOf className; Here, if objectName is an instance of className , the operator returns true . Otherwise, it returns false .

Should I use Instanceof?

instanceof is a binary operator we use to test if an object is of a given type. The result of the operation is either true or false. It's also known as a type comparison operator because it compares the instance with the type. Before casting an unknown object, the instanceof check should always be used.

What can I use instead of Instanceof in Java?

Having a chain of "instanceof" operations is considered a "code smell". The standard answer is "use polymorphism".


2 Answers

instanceof simply breaks the Open/Close principle. and/or Liskov substitution principle

If we are not enough abstract because of instanceof usage, each time a new subclass makes an entrance, the main code gathering the logic of the application might be updated. This is clearly not what we want, since it could potentially break the existing code and reduce its reusability.

Therefore, a good usage of polymorphism should be preferred over the basic use of conditional.

like image 95
Mik378 Avatar answered Sep 19 '22 13:09

Mik378


There's a good blog post called When Polymorphism Fails which is about this kind of scenario. Basically, you're right that it should be up to the Man to decide what to do with each kind of Animal. Otherwise, the code becomes fragmented and you end up violating principles such as Single Responsibility and Law of Demeter.

It wouldn't make sense to have code such as e.g. the following:

abstract class Animal {
    abstract void interactWith(Man man);
}
class Fish extends Animal {
    @Override
    void interactWith(Man man) {
        man.eat(this);
    }
}
class Dog extends Animal {
    @Override
    void interactWith(Man man) {
        man.playWith(this);
    }
}

In that example, we're putting Man's logic outside of the Man class.

The problem with instanceof is that if you have a large amount of Animals, you'll end up with a long if-else-if for every one of them. It's hard to maintain and prone to errors where e.g. a new type of Animal is added, but you forget to add it to the if-else-if chain. (The visitor pattern is partly a solution to the latter problem, because when you add a new type to the visitor class, all of the implementations stop compiling and you're forced to go update them all.)

However, we can still use polymorphism to make the code simpler and avoid instanceof.

For example, if we had a feeding routine such as:

if (animal instanceof Cat) {
    animal.eat(catFood);
} else if (animal instanceof Dog) {
    animal.eat(dogFood);
} else if (...) {
    ...
}

We could eliminate the if-else-if by having methods such as Animal.eat(Food) and Animal.getPreferredFood():

animal.eat(animal.getPreferredFood());

With methods such as Animal.isFood() and Animal.isPet(), the example in the question could be written without instanceof as:

if (animal.isFood()) {
    eatIt(animal);
} else if (animal.isPet()) {
    playWithIt(animal);
}
like image 23
Radiodef Avatar answered Sep 18 '22 13:09

Radiodef