Let's say I have a Projectile
class which acts as a base class for all projectiles in my game. This contains default values for maximum speed, gravity coefficient, bounce coefficient, etc.
public abstract class Projectile {
protected float maxSpeed = 100.0f;
protected float gravityCoefficient = 1.0f;
protected float bounceCoefficient = 1.0f;
...
}
I then have a bunch of subclasses, each of which may choose to override some of these default values.
Which is the better approach here?
1. Set field values in child constructor
public class Arrow {
public Arrow(){
super();
maxSpeed = 200.0f;
}
}
2. Make child override getter
public class Arrow {
public float getMaxSpeed(){
return 200.0f;
}
}
I am inclined to say that the first approach is better, since it means the field can be accessed directly without the need for any extra function calls. However, it does mean that the value is set twice during object creation, once by the parent and once by the child.
Am I missing anything here? Is there, perhaps, another approach?
Intuitively, the maximum speed of any particular projectile is unlikely to vary over its lifetime (even in the case where different instances of the same type can have different maximum speeds), therefore I would favour a final field for it. I would also favour making it final - I very rarely use non-private fields, other than for genuine constants.
As you have some state (the field) for Projectile
, I would avoid allowing the confusion of having the maximum speed has revealed by getMaxSpeed
differing from the field.
I would probably design it like this:
public abstract class Projectile {
private final float maxSpeed;
protected Projectile(float maxSpeed) {
this.maxSpeed = maxSpeed;
}
// Only if you really need this...
protected Projectile() {
this(200f);
}
public final getMaxSpeed() {
return maxSpeed;
}
}
public class Arrow extends Projectile {
public Arrow() {
super(100f);
}
}
The gravity coefficient and bounce coefficient may be treated in a similar way - or if all of these really act as "the same values for every instance of a particular type" you could introduce a new class to represent these constants, which separates the varying state of instances of a type from the constant restrictions/coefficients - and each instance could just have a final reference to an instance of that new class. Unfortunately Java (and at least some similar languages) don't really model this kind of hierarchy well. It's always an annoyance :(
See more on this question at Stackoverflow