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;
}
}
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.
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With