Search code examples
javaoverloadingsubclassextending-classes

Overload method with subclasses as parameters but have the method called as the superclass


I have an abstract class Animal, with two extending classes, Dog and Cat.

public abstract class Animal {
...
}
public class Dog extends Animal {
...
}
public class Cat extends Animal {
...
}

In another class, I have an ArrayList<Animal> animals that contains instances of both Cat and Dog.

In the class with the ArrayList<Animal>, I want to be able to overload a method doSomething() with either Dog d or Cat c as the parameters, but still be able to call them from the ArrayList of Animals. As follows:

public void aMethod(){
    ArrayList<Animals> animals = getTheAnimals();
    for (Animal a : animals){
        doSomething(a);
    }
}
public void doSomething(Dog a){
//a is an object of type dog
}
public void doSomething(Cat a){
//a is an object of type cat
}

Essentially, each method is acting as a 'selector' for which type of animal is being received by the method.

When trying as above, I get the following compilation error:

error: no suitable method found for doSomething(Animal)

I know I could use something like instanceOf or a.getClass().equals(type), but I have read that this is bad practice. This question differs slightly from this other question, as I want two separate methods, each with a different parameter.

EDIT: I am going to avoid using the Visitor Pattern as I don't think it really fits well into my actual implementation. Will move the doSomething() method into each class, and refactor to ensure this makes logical sense (each class performing actions that it should be responsible for). Thanks.


Solution

  • Yes instanceof and getclass would make your class dependent upon specific types and using such practices are not too good.

    But by having methods accepting Dog or Cat you again end up depending upon the concrete specific implementation.

    Better way is Define method in Animal interface performAction() . Provide implementation in both Dog and Cat. Now iterate your List of Animals and just invoke performAction() and polymorphically as per actual instance either Dog or Cat implemented method would be called. Later even if there is another implementation of Animal added in code you need not modify your code.

    This way you would be having Dog related logic in Dog class, Cat related logic in Cat class and not in any outside different class. This will help in respecting OCP and SRP (Open close and Single Responsibility principles).

    Also in case you wish to perform behavior later and your case is such that you know your implementations are fixed and want the using code to inject behavior later then I would recommend Visitor pattern, but still I feel this should not be abused, (design pattern are often not used but abused) sometime we force a pattern when not needed. Visitor pattern uses polymorphic to dispatch the first call to specific instance from where second dispatch calls the overloaded methods in class implementing the Visitor interface. (name can be different, I have mentioned Visitor to imply class implementing the concept of visitor) . Go for Visitor pattern like implementation only if needed and normal above polymorphic based approach do not fit the situation.