Consider the following class declaration:
class Person {
private String name;
private boolean male;
private Person spouse;
// etc.
}
To begin, we provide a principal constructor for initializing all fields:
class Person {
private String name;
private boolean male;
private Person spouse;
public
Person(String name, boolean male, Person spouse) {
this.name = name;
this.male = male;
this.spouse = spouse;
}
// etc.
}
We can provide additional derived constructors that initialize fields to default values:
class Person {
private String name;
private boolean male;
private Person spouse;
public Person(String name, boolean
male, Person spouse) {
this.name = name;
this.male = male;
this.spouse = spouse;
}
public
Person(String name, boolean male) {
this(name, male, null);
}
public Person(String name) {
this(name, true);
}
public Person() {
this("");
}
// etc.
}
The last constructor is parameterless and is often called the default constructor.
It's a good idea to provide a default constructor as many contexts assume one exists.
For example:
class Employee extends Person {
public Employee() {
super(); // Java calls this
implicitly
}
// etc.
}
Consider equipping every field with a getter (accessor) and a setter (mutator) method:
class Person {
private String name;
private boolean male;
private Person spouse;
//
getters:
public String getName() { return name;
}
public boolean isMale() { return male;
}
public Person getSpouse() { return
spouse; }
// setters:
public void setName(String newName) {
name = newName; }
public void setSpouse(Person newSpouse)
{ spouse = newSpouse; }
// etc.
}
Note that for Boolean fields the prefix of the accessor can be "is" instead of "get".
Of course some fields may be deemed read-only. These fields should not have setters.
For example, it makes sense that spouse should be a read-write field. People get married, divorced, and re-married all of the trime. The name field can be read-write since people do change their names occasionally. However, sex changes are exceedingly rare, and so the male field is read-only.
There is a tiny problem with our declaration of setSpouse. Notice that if the user isn't careful, then it is possible that John's spouse is Yoko, but Yoko's spouse is Paul.
What's wrong with the following declaration:
public void setSpouse(Person newSpouse) {
spouse = newSpouse;
newSpouse.setSpouse(this);
}
When a field contains a reference to another object (instead of a primitive value like a number or Boolean), then consider providing delegators instead of accessors and mutators.
For example, we might like to control the amount of information users can get about a person's spouse.
For example:
class Person {
private String name;
private boolean male;
private Person spouse;
//
delegators:
public String getSpouseName() { return
spouse.getName(); }
public void setSpouseSpouse() {
spouse.setSpouse(this); }
//etc.
}
This is especially critical for collection objects:
class Document {
private String Collection<String>
content;
public
void add(String word) { content.add(word); }
public void remove(String word) {
content.remove(word); }
public Iterator<String>
iterator() { return content.iterator(); }
public int size() { return
content.size(); }
// etc.
}
Note that with delegators we can control what words get added to the content of a document:
public void add(String word) {
if (dictionary.contains(word)) {
content.add(word);
} else {
content.add(word +
"(sp?)");
}
}