Why not use instanceof operator in OOP design?

前端 未结 4 1811
一整个雨季
一整个雨季 2020-11-28 12:33

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

4条回答
  •  栀梦
    栀梦 (楼主)
    2020-11-28 12:56

    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);
    }
    

提交回复
热议问题