Noch mehr Besucher

Im vorherigen Beitrag wurde das Visitor Pattern auf ein Enum angewendet, um das Enum nicht mit vielen Methoden zu überfrachten. Wie andere Klassen sollte ein Enum nicht gegen die Prinzipien des objektorientierten Designs verstoßen.

Die vorgestellte Lösung funktioniert zwar sehr gut, aber was soll der Entwickler machen, wenn neue Klassen die Bühne betreten? Nachdem er also ein Enum AccessLevel mit einer Menge interessanter Visitor Klassen verknüpft hat, kommt der Kunde mit neuen SecurityLevel und AnalyseLevel Anforderungen. Wie schön wäre es doch, wenn die bisherigen Visitor Klassen weiterverwendet werden könnten.

Etwas Generisches muss also her. Zuerst ein Visitor der verschiedene Enums besuchen kann.

public interface Visitor<E extends Enum<E>> {

  void visitEins(E e);

  void visitZwei(E e);

  void visitDrei(E e);
 }

Das Konstrukt sieht etwas seltsam aus, spiegelt aber die Natur der Enum Klassen wieder. Sie sind abgeleitet von der Klasse Enum und werden dieser als generischer Typ übergeben.

Das Enum, das vom Visitor besucht wird, muss sich der neuen Lage anpassen und bekommt eine etwas andere Methodensignatur.

public enum AccessLevel {
  ONE {
    public void accept(Visitor<AccessLevel> visitor) {
      visitor.visitOne(this);
    }
  },
  TWO {
    public void accept(Visitor<AccessLevel> visitor) {
      visitor.visitTwo(this);
    },
  THREE {
    public void accept(Visitor<AccessLevel> visitor) {
      visitor.visitThree(this);
    }
}

Das Enum bekommt einen Visitor, der genau auf seine Bedürfnisse zugeschnitten ist. Die Parameter der Methoden sind vom Type AccessLevel. Dazu noch ein generischer PrintVisitor, der auf beliebige Enums arbeitet.

public class PrintVisitor<E extends Enum<E>> implements Visitor<E> {

  private String print;

  public void visitOne(E level) {
    print = "LEVEL-" + this;
  }

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

  public void visitThree(E level) {
    print = "LEVEL-" + this;
  }

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

Dieser PrintVisitor kann nun auf beliebige Enums angewendet werden, die einen solchen generischen Visitor akzeptieren.

PrintVisitor<AccessLevel>().printLevel(AccessLevel.ONE);
PrintVisitor<SecurityLevel>().printLevel(SecurityLevel.A);