Notes About Java Part Three

ENUMs

Enumerations can help me create code that is readable and maintainable. However, in my last project I created a program design based on enums that proved to be too complex. This complexity increases the burden on maintenance in the aims of making the code maintainable. I need to find a balance between ease of reading and ease of updating.

I had not used Java’s Enums before. So, it took me some time to figure out how I wanted to design their use. I chose to make an Enums class that holds all the enums for the various classes and instantiate relevant enums in their respective classes.

The project models a toaster oven. I defined five enums but will show two here for brevity.

public class Enums {

  enum RackPosition {

    LOW(0), HIGH(1);

    RackPosition(int p) {

      position = p;

    }

    int position;

    public String toString() {

      return name();

    }

    public void printRackPositionInspectionReport() {

      System.out.println();
      System.out.print(toString());
      System.out.println();

    }

    public boolean isLow() {

      if (this == LOW) {

        return true;

      }

      return false;

    }

    public boolean isHigh() {

      if (this == HIGH) {

        return true;

      } 

      return false;

    }
  }

  enum OvenDoor {

    CLOSED, AJAR, OPEN;

    OvenDoor() {

      int door_position = this.ordinal();

    }

    int door_position;

    public String toString() {

      return "The door is " + name().toLowerCase() + ".";

    }

    public void printOvenDoorInspectionReport() {

      System.out.println();
      System.out.print(toString());
      System.out.println();

    }

    public boolean isClosed() {

      if (this == CLOSED) {

        return true;

      }

      return false;

    }

    public boolean isAjar() {

      if (this == AJAR) {

        return true;

      }

      return false;

    }

    public boolean isOpen() {

      if (this == OPEN) {

        return true;

      }

      return false;

    }
  }

The enums are instantiated in a class as follows.

public class AdjustableRack {
  
  private Enums.RackPosition rackPosition;

  public AdjustableRack() {

    rackPosition = Enums.RackPosition.LOW;

  }

  //Accessor control
  public Enums.RackPosition inspectRackPosition() {

    return rackPosition;

  }

  private boolean isLow() {

    return rackPosition.isLow();

  }

  private boolean isHigh() {
        
    return rackPosition.isHigh();

  }

  public void setRackPosition(Enums.RackPosition r, OvenDoor d) {

    if (d.inspectOvenDoor().isOpen()) {

      rackPosition = r;
        
    } else {

      d.inspectOvenDoor().printOvenDoorInspectionReport();

    }   
  }

  public void printRackPosition() {

    System.out.print(rackPosition.toString());

  }
}

The isLow and isHigh methods return the value of the rackPosition enum declared at the start of the AdjustableRack class.

setRackPosition relies on a class not present (OvenDoor) to determine if the oven door is open. If it is, then then the rack position is set to a new value allowed by the RackPosition enum declared in the Enums class.

To my mind, using enums in this way makes the intenion of the code clear. When the AdjustableRack constructor is called

  public AdjustableRack() {

    rackPosition = Enums.RackPosition.LOW;

  }

the position of the rack is obvious. However with five enums and potentially more at what point does maintaining the Enums class become too onerous? I was considering the possiblity of virtually constructing various parts of the enums, so they would not have to be defined in code. A slick class if I could write it, but very difficult to understand and extend.

The other possiblility is int values instead of enums. Rack position could be 0 and 1 where 0 is LOW and 1 is HIGH. The Enums class would not be necessary and it would be easy to write, but that choice looses some of the meaning given in things like the constructor above. While writing the code, this is not a high priority. The code is fresh in my mind and 0 being LOW and 1 being HIGH is obvious. Two years later this may not be the case. Did I make 0 HIGH or LOW, I might wonder. Furthermore, if someone else reading the code has to figure it out, they now have to remember that 0 is LOW and 1 is HIGH.

If the OvenDoor enum is considered, this meaning making becomes more difficult. Is OPEN 0? What value is AJAR? Why is CLOSED 2? Comments help reduce this confusion when reading the code, but a class where 0 is OPEN, 1 is AJAR, and 2 is CLOSED adds the burden of three more number/state associations to remember while maintaining the code. Conversely, the enums make it obvious when reading the code line by line.

At this point, I opted to get the project done and went with only ints. In the future, I will make a mixture of ints and enums, but I have not determined the best mix. Right at this moment, it seems to me that more complex enumerations like OvenDoor should be included. But what if I want to add a middle position to the rack. Now, LOW = 0, HIGH = 1, and MIDDLE = 2. Without refactoring, this is a confusing set of number/state associations, and would cause, at the very least, frustration and very possibly errors.