Let us presume we're dealing with a "classic" code-example:
I have the classes Animal, Cat, Dog, Horse and some more animals.
Animal is an abstract class which all the animals extend.
Additionally, I also have the enum AnimalType:
public enum AnimalType {
CAT, DOG, HORSE, ...
}
This is a scenario where using such an enum is neccessary. I am aware of instance testing and casting, and prefer using it to identification by enum. But it is needed here, so please refrain from turning this into a debate about that if possible.
Question:
Which of the following is the correct way to go and/or more efficient performance wise?:
a)
public abstract class Animal {
@Getter private final AnimalType type;
public Animal(AnimalType type) {
this.type = type;
}
}
or
b)
public abstract class Animal {
public Animal() {
}
public abstract AnimalType getType();
}
public class Cat extends Animal {
@Override
public AnimalType getType() {
return AnimalType.CAT;
}
}
In words: Should i store the enum of a child class in a member of the parent abstract class or make it "quasi-static" return from an abstract method?
CodePudding user response:
My preference is for approach a): storing the enum in the base class and providing a final getter for it.
The second approach does not force the contract that getType() will always return the real animal type, because an implementation could look like this:
public class DraftAnimal extends Animal
{
…
@Override
public final AnimalType getType()
{
// DO NOT DO THIS!
return today.equals( christmas ) ? AnimalType.REINDEER : AnimalType.HORSE;
}
}
Confessed, the sample looks silly … but you want to block those silly ideas right from the design.
CodePudding user response:
Well, I think you shouldn't care about performance in this case, because both memory footprint of your objects and cost of calling getters are likely to be the same (very cheap).
As soon as you are using abstract class with some common functionality I'd suggest approach b) for consistency with the rest of the code (in case we have only those two options you suggest).
Alternatively, you could have protected final field in your abstract class along with the getter. Something like this:
public abstract class Animal {
@Getter protected final AnimalType type;
public Animal(AnimalType type) {
this.type = type;
}
}
public class Cat extends Animal {
public Cat() {
super(AnimalType.CAT);
}
}
This approach encapsulates all the common code in your abstract class, but requires the type to be explicitly passed in constructors of inherited classes.
