Canonical Form for Fields

Consider the following class declaration:

class Person {
   private String name;
   private boolean male;
   private Person spouse;
   // etc.
}

Initializing Fields

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.
}

Accessors and Mutators

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);
}

Delegators

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?)");
   }
}