Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Acceptable use of instanceof [duplicate]

I'm new to Java and struggling with a design problem. I know use of instanceof may indicate a design flaw and I understand the often given Animal/Dog/Cat classes as example, replacing bark() and meow() with makenoise() etc.

My question is, what is a sensible design if I need to call methods which do not have a corresponding method depending on the type of subclass? For example, what if I want to call a new method biteleash() if the class is a Dog but do nothing at all if it's a Cat?

I did consider having biteleash() in Animal which does nothing, and overriding it in Dog, but there are methods many like this so it seems a clunky solution. In a similar vein, what if the caller needs to do something different depending on which subclass it has hold of, eg. terminate if subclass is a Cat? Is instanceof acceptable here, or is there a better way?

public class Animal {

    String name;

    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void makeNoise() {
        System.out.println("Some noise for a generic animal!");
    }

}

public class Cat extends Animal {

    public Cat(String name) {
        super(name);
    }

    @Override
    public void makeNoise() {
        System.out.println("Meow");
    }
}

public class Dog extends Animal {

    public Dog(String name) {
        super(name);
    }

    @Override
    public void makeNoise() {
        System.out.println("Woof");
    }

    public void biteLeash() {
        System.out.println("Leash snapped!");
    }
}

import java.util.Random;

public class CodeExample {


    public static void main(String[] args) {

        Animal animal = getSomeAnimal();
        System.out.println("My pet is called " + animal.getName());
        animal.makeNoise();

        if (animal instanceof Dog) {
            Dog dog = (Dog) animal;
            dog.biteLeash();
            // do lots of other things because animal is a dog
            // eg. sign up for puppy training lessons
        }
    }

    private static Animal getSomeAnimal() {
        Animal animal;
        Random randomGenerator = new Random();
        int randomInt = randomGenerator.nextInt(100);      
        if (randomInt < 50) {
            animal = new Dog("Rover");
        }
        else {
            animal = new Cat("Tiddles");
        }
        return animal;
    }
}
like image 542
scatter Avatar asked May 15 '15 09:05

scatter


People also ask

When should you not use Instanceof?

The problem with instanceof is that if you have a large amount of Animal s, 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.

What can I use instead of Instanceof?

The isInstance method is equivalent to instanceof operator. The method is used in case of objects are created at runtime using reflection. General practice says if the type is to be checked at runtime then use the isInstance method otherwise instanceof operator can be used.

Why does instanceof return false?

If the original err is created in a different context, this check will return false. This is because instanceof moves down the prototype chain testing whether the instance we're checking our variable ( err ) is one of the prototypes.

Is Instanceof a good practice?

Probably most of you have already heard that using “instanceof” is a code smell and it is considered as a bad practice. While there is nothing wrong in it and may be required at certain times, but the good design would avoid having to use this keyword.


2 Answers

Composition will help you here, and is idiomatic in Java.

Design an interface called, say, Leashable. This is implemented by a Dog, but not a Cat.

Rather than using instanceof, you can attempt a reference cast to Leashable to see if it's implemented by your particular object.

In my opinion, you should continue in a similar vein: Build a NoisyAnimal interface too. Perhaps even just Noisy as why should noisiness be pertinent to only animals? Implementing that for a Parrot, say, will have technical challenges beyond a Cat or Dog. Good maintainable programs isolate areas of complexity and composition helps you achieve that.

like image 133
Bathsheba Avatar answered Oct 27 '22 02:10

Bathsheba


You shouldn't use concrete classes. Instanceof itself isnt a problem. It exists for a reason. You should use interfaces for loose coupling i.e. your code shouldnt be dependent on concrete class implementations. I suggest you using interfaces wherever possible (i.e. IAnimal instead of Animal)

Instead of checking for Dog, you should use an interface like ILeashable (yeah a bit ridiculous for a name lol), then:

public interface ILeashable {
   //add other methods which is connected to being on a leash
   void biteLeash();
}

class Dog implements ILeashable {...}

Also there is no one way of doing this, there are certain patterns i.e. decorators or Dependency Inversion which might help you in this case.

like image 37
breakline Avatar answered Oct 27 '22 02:10

breakline