Reputation: 10665
I have an abstract class Compartment
with variables label
tariff
totalSeats
and seatsAvailable
as shown below. I am setting these variables by calling super()
from the constructor of subclass FirstClassCompartment
. I have few questions regarding my code.
First of all, is this a right approach to set variables using super class constructor or I should create a setter method in super class to set these variables.
Second, is it bad coding to access the variables of super class directly and not using getter/setter methods.
Last, Value of variable seatsAvailable
in super class depends upon the variable seatsReserved
in sub class like this seatsAvailable = totalSeats - seatsReserved
. Might this cause code maintenance or flexibility issues in the future?
public abstract class Compartment {
protected final char label;
protected final double tariff;
protected final int totalSeats;
protected int seatsAvailable;
public Compartment(char label, double tariff, int totalSeats) {
this.label = label;
this.tariff = tariff;
this.totalSeats = totalSeats;
}
public char getLabel() {
return label;
}
public int getTotalSeats() {
return totalSeats;
}
public void setSeatsAvailableLessByOne() {
seatsAvailable--;
}
public abstract int getSeatsAvailable();
public abstract double getTariff();
}
public class FirstClassCompartment extends Compartment {
protected final int seatsReserved;
public FirstClassCompartment(char label, double tariff, int totalSeats, int seatsReserved) {
super(label, tariff, totalSeats);
this.seatsReserved = seatsReserved;
seatsAvailable = totalSeats - seatsReserved;
}
@Override
public double getTariff() {
return tariff + tariff * .13;
}
@Override
public int getSeatsAvailable() {
return seatsAvailable;
}
}
Upvotes: 0
Views: 106
Reputation: 3592
I use to declare my fields with 'package' visibility. Its the default visibility, it can be accessed by inhered classes and same package classes. It helps a lot when you are unit testing, because test are written in the same package.
Indiscriminate use of getters/setters breaks encapsulation in my opinion. You are exposing all by fields default, when probably its not needed.
If your variables are setted only one time in constructor, then they should be 'final'.
If a setter has some logic, and in a future you may need to override it, then make it overridable, but its not a good practice to use an overridable method inside a constructor.
Upvotes: 0
Reputation: 20520
First question: this is absolutely the right way to do it. Invoke the superclass constructor, and pass the relevant arguments.
Second question: this is in part a stylistic thing. It's good practice not to make the fields directly available to all and sundry, so you wouldn't want them to be public
, but having them available to your own subclasses is not disastrous. It would be quite reasonable to make them available via getters and setters, though, and certainly if you had fields that you wanted to be readable by the subclass but not writable, then a getter would be appropriate.
Third question: there's no problem here. The superclass is abstract
, so you'd expect the subclass implementation to fill in some of the gaps. But since the seatsAvailable
logic is so simple (a subtraction), you might think about getting rid of the seatsAvailable
field entirely, and just having
@Override
public int getSeatsAvailable() {
return totalSeats - seatsReserved;
}
That way, it will be calculated on the fly, and you won't have to worry about keeping this field in sync with the others.
Upvotes: 1
Reputation: 3749
Looks good to me, I would probably rename the method setSeatsAvailableLessByOne
to something more meaningful, like decrementSeatsAvailable
if you want to have it at all.
Edit
You're right that having a seatsAvailable
is redundant. You could just move seatsReserved
and the derived value to the super class tho'. It's unlikely that there would be other ways to implement the getSeatsAvailable
method, and even if there was, you could still override it, in these specific cases.
Upvotes: 0