Home Object methods and constructors
Extra public functionality
You should not include extra public methods beyond what the spec instructs you to include. Any helper methods you make must be kept private.
The reasoning here is that by making helper methods public, you're exposing implementation detail that the client shouldn't be really need to know about.
If you want to intentionally add public functionality to extend the behavior of your class, you should not do that. When grading we have to be very strict to ensure that we're equally fair to all students, and even if your extension is a good idea, we'll probably have to dock you points because you've ended up ignoring portions of the spec.
Duplicate constructors
When writing classes with multiple constructors that share many similarities, you should always try and structure your constructors such that they all delegate to one single, general constructor instead of repeating your initialization logic.
For example, say we had an object which we use to represent a spaceship, like so:
public class Spaceship { private List<String> crew; private double fuelLeft; private String name; public Spaceship() { // ??? } }
There are multiple valid ways we could initialize the initial state of this spaceship. We might want to start by simply give the spaceship a name, leaving the crew and fuel remaining empty to start with. Alternatively, we might want to be super-detailed and give the spaceship the amount of fuel it has and its crew members to start with. Or perhaps we want to make use of some futuristic cloning technology and copy another spaceship and its crew outright. Each of these are valid (though possibly ethically dubious) ways of setting up the initial state of a spaceship, which means we should have a constructor for each:
public class Spaceship { private List<String> crew; private double fuelLeft; private String name; public Spaceship(String name) { this.crew = new ArrayList<String>(); this.fuelLeft = 0; this.name = name; } public Spaceship(Spaceship other) { // clone the crew this.crew = new ArrayList<String>(other.crew); // violate conservation of energy because science this.fuelLeft = other.fuelLeft; // copyright violation? this.name = other.name; } public Spaceship(List<String> crew, int fuelLeft, String name) { if (fuelLeft < 0) { throw new IllegalArgumentException("Cannot provide negative fuel"); } this.crew = crew; this.fuelLeft = fuelLEft; this.name = name; } }
However, the problem with doing something like this is that we have a lot of redundancy and duplicate code. We can fix this by using the this
keyword like so:
public class Spaceship { private List<String> crew; private double fuelLeft; private String name; public Spaceship(String name) { this(new ArrayList<String<(), 0, name); } public Spaceship(Spaceship other) { // clone the crew, violate conservation of energy, violate copyright this(new ArrayList<String>(other.crew), other.fuelLeft, other.name); } public Spaceship(List<String> crew, int fuelLeft, String name) { if (fuelLeft < 0) { throw new IllegalArgumentException("Cannot provide negative fuel"); } this.crew = crew; this.fuelLeft = fuelLEft; this.name = name; } }
Now, we've isolated all of our initialization and setup logic into a single constructor, almost completely reducing all redundancy in the process.
Method independence
When writing objects, you should take care to ensure that no single method relies on any other method being called first, or in any particular order.
The only thing you may assume is that one of your constructors will be the very first thing that is run. Apart from that, anything goes.
A common mistake students make is to assume that the objects they're writing will always be called and executed in some specific order. However, that is not the case.
While the test classes we give you will call your methods in a specific order, you should design your classes so that they don't rely on that and could work with any arbitrary client.
So, if you have a class with three methods named methodA
,
methodB
, and methodC
, you should be prepared for the client
to do something crazy like call methodA
1000 times in a row, or alternate
between calling methodB
and methodC
three hundred times, pause
for a minute, repeat, etc...
No matter what the client tries, your code must do something reasonable in response.