Zu Besuch bei den Enums

Die Enums in Java sind eine typsichere Alternative zu den früher verwendeten Konstanten.

public class Test {
  private static final String LEVEL_ONE = "one";
  private static final String LEVEL_TWO = "two";
  // ...
}

Mit solchen Konstanten hat man die üblichen Probleme, dass man sie überall fehlerhafter Weise einsetzen oder anstelle der Konstanten andere Werte des Typs verwenden kann. Besser also der Einsatz von Enums, die als echter Typ nur die definierten Konstanten zulassen.

public class Test {
  private enum Level { ONE, TWO }
  // ...
}

Enums erlauben aber mehr als nur die Definition von Konstanten, sie können auch zusätzliche Methoden enthalten, die entweder für alle Elemente gelten oder aber für einzelne Elemente überschrieben werden können.

public enum Level {
  ONE {
    public String print() {
    return "LEVEL-A";
    }
  },
  TWO,
  THREE;

  public String print() {
    return "LEVEL-" + this;
  }
}

Selbstverständlich kann man auch mit diesen Sprachmittel seinen Schindluder treiben. Kein Sprachkonstrukt ist so sicher, dass nicht ein unfähiger Entwickler eine Zeitbombe daraus bauen kann. Beliebt sind bei den Enums insbesondere Membervariablen zur Speicherung von Zwischenergebnissen oder Zuständen. Dabei wird dann leicht vergessen, dass andere Software Entwickler von Enums eine gewisse Konstanz erwarten.

Erkennt ein Novize die Möglichkeiten der Enums, dann ist Vorsicht geboten, denn sehr schnell expandiert das obige Beispiel und erhält zusätzliche Methoden die XML, HTML und JSON Darstellungen zurückliefern. Außerdem werden neue Konstanten FOUR und FIVE hinzugefügt und die Utility-Methoden next() und previous() ergänzt, um von einer Enum Konstante zur anderen zu wandern.

Ein schönes Pattern, um der wachsenden Zahl von Methoden entgegenzuwirken, ist das Visitor Pattern. Die spezielle Logik ist in Klassen ausgegliedert, die für unterschiedliche Besucher eigene Methoden bereitstellen. Eine Visitor-Variante für das obige Beispiel:

public enum Level {
  ONE {
    public void accept(Visitor visitor) {
      visitOne(this);
    }
  },
  TWO {
    public void accept(Visitor visitor) {
      visitTwo(this);
    },
  THREE {
    public void accept(Visitor visitor) {
      visitThree(this);
    }
  };

  public abstract void accept(Visitor visitor);
}

Der Visitor ist ein Interface, das für die Konstanten Methoden bereitstellt, die diese aufrufen können. Dabei geben sie sich selber als Parameter der Methode an. Im Falle einfacher Enums kann man dies natürlich auch vernachlässigen, da die Konstante der Methode keine zusätzliche Information liefert.

public interface Visitor {

  void visitOne(Level level);

  void visitTwo(Level level);

  void visitThree(Level level);
}

Um eine unser Beispiel zu vervollständigen fehlt nur noch die Implementierung eines Visitors.

public class PrintVisitor extends Visitor {
  private String print;

  public void visitOne(Level level) {
    print = "LEVEL-A";
  }

  public void visitTwo(Level level) {
    print = "LEVEL-" + this;
  }

  public void visitThree(Level level) {
    print = "LEVEL-THREE";
  }

  public String printLevel(Level level) {
    level.accept(this);
    return print;
  }
}

Für dieses Beispiel eine Menge Code, aber schon die Erweiterung für XML, HTML und JSON bedeutet keine Veränderung mehr am Enum, da ja die neue Funktionalität in den Visitor Implementierungen XmlVisitor, HtmlVisitor und JsonVisitor gebündelt wird.