Search code examples
javasubclasssuperclass

Avoid instanceof but restrict function parameter to a set of subclasses of a superclass


In other words how to force a method to only use subclasses of the given input parameter which is a superclass?

Example:

public class Animal {
    ...
}

public class Dog extends Animal {
...
}

public class Cat extends Animal {
...
}

public class Test {
   ...
   public void makeSound(Animal animal) throws Exception{
      if(animal instanceof Dog){
         System.out.println("bark");
      } else if (animal instanceof Cat) {
        System.out.println("meow");
      } else {
        throw new Exception ("Not valid subclass of Animal");
      }
   }
}

The code above seems somehow wrong, is there a better, more efficient or generic way?


Solution

  • To avoid doing the instanceof check for each subtype, you can create an abstract makeSound() method in Animal class, and override in all the subclasses. I would make the Animal class abstract, as it really is an abstract entity in your scenario:

    abstract class Animal {
        abstract void makeSound();
    }
    
    class Dog extends Animal {
        void makeSound() { System.out.println("Bark"); }
    }
    
    class Cat extends Animal {
        void makeSound() { System.out.println("Meow"); }
    }
    

    and then in Test class, just invoke makeSound on Animal reference. It will call appropriate overridden method based on actual instance:

    public void makeSound(Animal animal){
        animal.makeSound();
    }
    

    Now, everytime you add a new subtype of Animal, you just need to override makeSound() in that class. With abstract method, you will be forced to do that. And keep the Test#makeSound() method unmodified.